From d8f644ca3d4ce62f2ef41d4aacb52f5bb1221df3 Mon Sep 17 00:00:00 2001 From: vsr Date: Thu, 25 Nov 2010 12:44:43 +0000 Subject: [PATCH] Merge from V5_1_main branch 24/11/2010 --- clean_configure | 2 +- configure.ac | 30 +- doc/Makefile.am | 2 +- doc/docutils/Makefile.am | 91 + doc/docutils/conf.py | 200 + doc/docutils/docapi.rst | 17 + doc/docutils/index.rst | 14 + doc/docutils/overview.rst | 24 + doc/salome/gui/SMESH/Makefile.am | 40 +- doc/salome/gui/SMESH/doxyfile.in | 1 + doc/salome/gui/SMESH/doxyfile_py.in | 5 +- .../gui/SMESH/images/2d_from_3d_dlg.png | Bin 0 -> 21853 bytes .../gui/SMESH/images/2d_from_3d_ico.png | Bin 0 -> 406 bytes .../gui/SMESH/images/2d_from_3d_menu.png | Bin 20123 -> 24838 bytes .../gui/SMESH/images/a-averagelength.png | Bin 13679 -> 13595 bytes doc/salome/gui/SMESH/images/a-clipping2.png | Bin 21116 -> 17327 bytes .../gui/SMESH/images/advanced_mesh_infos.png | Bin 24892 -> 28432 bytes doc/salome/gui/SMESH/images/bnd_box.png | Bin 0 -> 17441 bytes .../gui/SMESH/images/bnd_box_preview.png | Bin 0 -> 56083 bytes doc/salome/gui/SMESH/images/creategroup.png | Bin 30825 -> 35346 bytes doc/salome/gui/SMESH/images/duplicate01.png | Bin 0 -> 11580 bytes doc/salome/gui/SMESH/images/duplicate02.png | Bin 0 -> 13187 bytes .../gui/SMESH/images/duplicate_nodes.png | Bin 0 -> 1057 bytes doc/salome/gui/SMESH/images/editgroup.png | Bin 36255 -> 37239 bytes doc/salome/gui/SMESH/images/elem_info.png | Bin 0 -> 907 bytes doc/salome/gui/SMESH/images/eleminfo1.png | Bin 18764 -> 19088 bytes doc/salome/gui/SMESH/images/eleminfo2.png | Bin 33198 -> 36810 bytes doc/salome/gui/SMESH/images/formula5.png | Bin 0 -> 5184 bytes .../gui/SMESH/images/hexotic_parameters.png | Bin 21710 -> 23172 bytes .../gui/SMESH/images/hyp_source_edges.png | Bin 0 -> 13394 bytes .../gui/SMESH/images/hyp_source_faces.png | Bin 0 -> 13297 bytes .../SMESH/images/hypo_quad_params_dialog.png | Bin 0 -> 21190 bytes doc/salome/gui/SMESH/images/image42.png | Bin 0 -> 857 bytes doc/salome/gui/SMESH/images/image43.png | Bin 0 -> 965 bytes doc/salome/gui/SMESH/images/image49.png | Bin 861 -> 988 bytes doc/salome/gui/SMESH/images/image79.jpg | Bin 49431 -> 57934 bytes doc/salome/gui/SMESH/images/image99.gif | Bin 10733 -> 15691 bytes .../SMESH/images/max_element_length_2d.png | Bin 0 -> 18345 bytes .../SMESH/images/max_element_length_3d.png | Bin 0 -> 19127 bytes doc/salome/gui/SMESH/images/mergenodes.png | Bin 36395 -> 35421 bytes .../gui/SMESH/images/mergenodes_auto.png | Bin 18806 -> 24225 bytes doc/salome/gui/SMESH/images/meshtopass.png | Bin 19997 -> 17937 bytes doc/salome/gui/SMESH/images/min_distance.png | Bin 0 -> 22662 bytes .../gui/SMESH/images/min_distance_preview.png | Bin 0 -> 116380 bytes doc/salome/gui/SMESH/images/moving_nodes1.png | Bin 15776 -> 7760 bytes doc/salome/gui/SMESH/images/moving_nodes2.png | Bin 20232 -> 6900 bytes doc/salome/gui/SMESH/images/netgen2d.png | Bin 7772 -> 0 bytes doc/salome/gui/SMESH/images/netgen2d3d.png | Bin 0 -> 36615 bytes .../gui/SMESH/images/netgen2d3d_simple.png | Bin 0 -> 32547 bytes .../gui/SMESH/images/netgen3d_local_size.png | Bin 0 -> 16229 bytes .../gui/SMESH/images/netgen3d_simple.png | Bin 26853 -> 0 bytes .../gui/SMESH/images/remove_nodes_icon.png | Bin 0 -> 720 bytes .../SMESH/images/remove_orphan_nodes_icon.png | Bin 0 -> 807 bytes .../gui/SMESH/images/removeorphannodes.png | Bin 0 -> 8075 bytes .../gui/SMESH/images/split_into_tetra.png | Bin 24682 -> 24205 bytes .../gui/SMESH/input/1d_meshing_hypo.doc | 12 +- .../gui/SMESH/input/2d_meshing_hypo.doc | 47 +- doc/salome/gui/SMESH/input/about_filters.doc | 31 + doc/salome/gui/SMESH/input/about_hypo.doc | 4 +- .../SMESH/input/about_quality_controls.doc | 22 +- .../SMESH/input/adding_nodes_and_elements.doc | 28 +- .../SMESH/input/adding_quadratic_elements.doc | 28 +- .../gui/SMESH/input/additional_hypo.doc | 9 +- doc/salome/gui/SMESH/input/area.doc | 3 +- doc/salome/gui/SMESH/input/aspect_ratio.doc | 12 +- .../gui/SMESH/input/aspect_ratio_3d.doc | 4 +- .../gui/SMESH/input/basic_meshing_algos.doc | 1 + doc/salome/gui/SMESH/input/clipping.doc | 13 +- .../gui/SMESH/input/creating_groups.doc | 5 +- .../gui/SMESH/input/double_nodes_page.doc | 70 + .../gui/SMESH/input/grouping_elements.doc | 2 +- doc/salome/gui/SMESH/input/index.doc | 13 +- doc/salome/gui/SMESH/input/length_2d.doc | 4 +- .../gui/SMESH/input/make_2dmesh_from_3d.doc | 60 +- .../gui/SMESH/input/max_element_length_2d.doc | 29 + .../gui/SMESH/input/max_element_length_3d.doc | 30 + doc/salome/gui/SMESH/input/measurements.doc | 71 + doc/salome/gui/SMESH/input/merging_nodes.doc | 17 +- doc/salome/gui/SMESH/input/mesh_infos.doc | 89 +- .../gui/SMESH/input/mesh_through_point.doc | 35 +- doc/salome/gui/SMESH/input/minimum_angle.doc | 3 +- .../gui/SMESH/input/modifying_meshes.doc | 11 +- doc/salome/gui/SMESH/input/moving_nodes.doc | 36 - .../gui/SMESH/input/netgen_2d_3d_hypo.doc | 23 +- .../gui/SMESH/input/pattern_mapping.doc | 215 +- .../input/removing_nodes_and_elements.doc | 37 +- .../SMESH/input/selection_filter_library.doc | 16 + doc/salome/gui/SMESH/input/skew.doc | 3 +- .../gui/SMESH/input/smeshpy_interface.doc | 2 + doc/salome/gui/SMESH/input/smeshpypkg.doc | 14 + doc/salome/gui/SMESH/input/split_to_tetra.doc | 2 +- doc/salome/gui/SMESH/input/taper.doc | 4 +- .../SMESH/input/tui_defining_hypotheses.doc | 112 +- doc/salome/gui/SMESH/input/tui_filters.doc | 594 + .../gui/SMESH/input/tui_grouping_elements.doc | 8 +- .../gui/SMESH/input/tui_measurements.doc | 84 + .../gui/SMESH/input/tui_modifying_meshes.doc | 38 +- .../gui/SMESH/input/tui_quality_controls.doc | 132 +- .../SMESH/input/tui_transforming_meshes.doc | 234 + .../gui/SMESH/input/use_existing_algos.doc | 58 + doc/salome/gui/SMESH/input/volume.doc | 4 +- doc/salome/gui/SMESH/input/warping.doc | 4 +- idl/Makefile.am | 6 +- idl/SMESH_BasicHypothesis.idl | 75 + idl/SMESH_Filter.idl | 35 +- idl/SMESH_Gen.idl | 4 +- idl/SMESH_Group.idl | 19 +- idl/SMESH_Measurements.idl | 61 + idl/SMESH_Mesh.idl | 15 + idl/SMESH_MeshEditor.idl | 90 +- resources/Makefile.am | 15 +- resources/SalomeApp.xml | 6 + resources/StdMeshers.xml | 28 +- resources/advanced_mesh_info.png | Bin 973 -> 988 bytes resources/mesh_bounding_box.png | Bin 0 -> 3449 bytes resources/mesh_duplicate_nodes.png | Bin 0 -> 914 bytes resources/mesh_duplicate_nodes_with_elem.png | Bin 0 -> 891 bytes resources/mesh_elem_info.png | Bin 0 -> 907 bytes resources/mesh_max_element_length_2d.png | Bin 0 -> 857 bytes resources/mesh_max_element_length_3d.png | Bin 0 -> 965 bytes resources/mesh_min_dist.png | Bin 0 -> 3360 bytes resources/mesh_quadrangle_quadpref.png | Bin 0 -> 368 bytes .../mesh_quadrangle_quadpref_reversed.png | Bin 0 -> 357 bytes resources/mesh_quadrangle_reduced.png | Bin 0 -> 459 bytes resources/mesh_quadrangle_standard.png | Bin 0 -> 308 bytes resources/mesh_quadrangle_triapref.png | Bin 0 -> 391 bytes resources/mesh_rem_orphan_nodes.png | Bin 0 -> 807 bytes src/Controls/SMESHControls.cxx | 2 + src/Controls/SMESH_Controls.cxx | 573 +- src/Controls/SMESH_ControlsDef.hxx | 62 +- src/DriverUNV/DriverUNV_R_SMDS_Mesh.cxx | 36 +- src/DriverUNV/UNV2412_Structure.cxx | 191 +- src/DriverUNV/UNV2417_Structure.cxx | 7 - src/DriverUNV/UNV_Test.cxx | 7 - src/DriverUNV/UNV_Utilities.cxx | 6 - src/Makefile.am | 5 +- src/OBJECT/Makefile.am | 7 +- src/OBJECT/SMESH_Actor.cxx | 184 +- src/OBJECT/SMESH_Actor.h | 18 +- src/OBJECT/SMESH_ActorDef.h | 20 +- src/OBJECT/SMESH_DeviceActor.cxx | 22 +- src/OBJECT/SMESH_DeviceActor.h | 6 +- src/OBJECT/SMESH_FaceOrientationFilter.cxx | 5 +- src/OBJECT/SMESH_FaceOrientationFilter.h | 5 +- src/OBJECT/SMESH_Object.cxx | 2 +- src/OBJECT/SMESH_PreviewActorsCollection.cxx | 1 - src/OBJECT/SMESH_ScalarBarActor.cxx | 923 ++ src/OBJECT/SMESH_ScalarBarActor.h | 246 + src/PluginUtils/GeomSelectionTools.cxx | 42 + src/PluginUtils/GeomSelectionTools.h | 8 + src/SMDS/SMDS_Mesh.cxx | 60 +- src/SMDS/SMDS_Mesh.hxx | 10 +- src/SMDS/SMDS_MeshElement.hxx | 2 +- src/SMDS/SMDS_MeshNode.cxx | 5 - src/SMDS/SMDS_MeshNode.hxx | 12 +- src/SMDS/SMDS_VolumeTool.cxx | 106 +- src/SMDS/SMDS_VolumeTool.hxx | 11 +- src/SMESH/SMESH_Algo.cxx | 6 +- src/SMESH/SMESH_Algo.hxx | 9 +- src/SMESH/SMESH_Block.cxx | 10 +- src/SMESH/SMESH_Block.hxx | 2 +- src/SMESH/SMESH_Gen.cxx | 2 +- src/SMESH/SMESH_Group.cxx | 2 +- src/SMESH/SMESH_Group.hxx | 1 - src/SMESH/SMESH_HypoFilter.cxx | 23 +- src/SMESH/SMESH_HypoFilter.hxx | 7 +- src/SMESH/SMESH_Hypothesis.cxx | 18 + src/SMESH/SMESH_Hypothesis.hxx | 5 + src/SMESH/SMESH_Mesh.cxx | 32 +- src/SMESH/SMESH_Mesh.hxx | 23 +- src/SMESH/SMESH_MeshEditor.cxx | 933 +- src/SMESH/SMESH_MeshEditor.hxx | 69 +- src/SMESH/SMESH_MesherHelper.cxx | 366 +- src/SMESH/SMESH_MesherHelper.hxx | 33 +- src/SMESH/SMESH_OctreeNode.cxx | 25 +- src/SMESH/SMESH_OctreeNode.hxx | 26 +- src/SMESH/SMESH_Pattern.cxx | 7 +- src/SMESH/SMESH_Pattern.hxx | 4 +- src/SMESH/SMESH_subMesh.cxx | 75 +- src/SMESHDS/SMESHDS_Group.cxx | 2 +- src/SMESHDS/SMESHDS_Group.hxx | 2 +- src/SMESHDS/SMESHDS_GroupBase.hxx | 2 +- src/SMESHDS/SMESHDS_GroupOnGeom.cxx | 2 +- src/SMESHDS/SMESHDS_GroupOnGeom.hxx | 2 +- src/SMESHDS/SMESHDS_Mesh.cxx | 72 +- src/SMESHDS/SMESHDS_Mesh.hxx | 35 +- src/SMESHFiltersSelection/SMESH_Type.h | 5 + .../SMESH_TypeFilter.cxx | 31 + src/SMESHGUI/Makefile.am | 30 +- src/SMESHGUI/SMESHGUI.cxx | 1274 +- src/SMESHGUI/SMESHGUI.h | 41 +- src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx | 64 +- .../SMESHGUI_AddQuadraticElementDlg.cxx | 36 +- src/SMESHGUI/SMESHGUI_BuildCompoundDlg.cxx | 42 +- src/SMESHGUI/SMESHGUI_ClippingDlg.cxx | 792 +- src/SMESHGUI/SMESHGUI_ClippingDlg.h | 116 +- src/SMESHGUI/SMESHGUI_ComputeDlg.cxx | 44 +- src/SMESHGUI/SMESHGUI_ComputeDlg.h | 2 - .../SMESHGUI_CreatePolyhedralVolumeDlg.cxx | 84 +- src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx | 580 + src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.h | 119 + src/SMESHGUI/SMESHGUI_FilterDlg.cxx | 334 +- src/SMESHGUI/SMESHGUI_FilterDlg.h | 1 + src/SMESHGUI/SMESHGUI_FindElemByPointDlg.cxx | 4 +- src/SMESHGUI/SMESHGUI_GroupDlg.cxx | 329 +- src/SMESHGUI/SMESHGUI_GroupDlg.h | 10 +- src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx | 12 +- src/SMESHGUI/SMESHGUI_Hypotheses.cxx | 68 +- src/SMESHGUI/SMESHGUI_Make2DFrom3DOp.cxx | 462 +- src/SMESHGUI/SMESHGUI_Make2DFrom3DOp.h | 83 +- src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx | 203 +- src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.h | 9 +- src/SMESHGUI/SMESHGUI_Measurements.cxx | 1231 ++ src/SMESHGUI/SMESHGUI_Measurements.h | 172 + ..._EditMeshDlg.cxx => SMESHGUI_MergeDlg.cxx} | 167 +- ...HGUI_EditMeshDlg.h => SMESHGUI_MergeDlg.h} | 24 +- src/SMESHGUI/SMESHGUI_MeshInfo.cxx | 1335 ++ src/SMESHGUI/SMESHGUI_MeshInfo.h | 220 + src/SMESHGUI/SMESHGUI_MeshInfosDlg.cxx | 4 +- src/SMESHGUI/SMESHGUI_MeshOp.cxx | 99 +- src/SMESHGUI/SMESHGUI_MeshUtils.cxx | 51 + src/SMESHGUI/SMESHGUI_MeshUtils.h | 10 + src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx | 4 +- src/SMESHGUI/SMESHGUI_NodesDlg.cxx | 36 +- .../SMESHGUI_Preferences_ScalarBarDlg.cxx | 110 +- .../SMESHGUI_Preferences_ScalarBarDlg.h | 10 + src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx | 28 +- src/SMESHGUI/SMESHGUI_RemoveNodesDlg.cxx | 26 +- src/SMESHGUI/SMESHGUI_RotationDlg.cxx | 46 +- src/SMESHGUI/SMESHGUI_ScaleDlg.cxx | 96 +- src/SMESHGUI/SMESHGUI_Selection.cxx | 45 +- src/SMESHGUI/SMESHGUI_Selection.h | 3 + src/SMESHGUI/SMESHGUI_SpinBox.cxx | 4 +- src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx | 42 +- src/SMESHGUI/SMESHGUI_TranslationDlg.cxx | 46 +- src/SMESHGUI/SMESHGUI_Utils.cxx | 14 + src/SMESHGUI/SMESHGUI_Utils.h | 3 + src/SMESHGUI/SMESHGUI_VTKUtils.cxx | 115 +- src/SMESHGUI/SMESHGUI_VTKUtils.h | 10 + src/SMESHGUI/SMESH_images.ts | 30 +- src/SMESHGUI/SMESH_msg_en.ts | 11016 ++++++++-------- src/SMESHGUI/SMESH_msg_fr.ts | 5346 ++++++++ src/SMESH_I/Makefile.am | 4 +- src/SMESH_I/SMESH_2smeshpy.cxx | 91 +- src/SMESH_I/SMESH_DumpPython.cxx | 50 +- src/SMESH_I/SMESH_Filter_i.cxx | 190 +- src/SMESH_I/SMESH_Filter_i.hxx | 69 +- src/SMESH_I/SMESH_Gen_i.cxx | 193 +- src/SMESH_I/SMESH_Gen_i.hxx | 5 +- src/SMESH_I/SMESH_Gen_i_1.cxx | 37 +- src/SMESH_I/SMESH_Group_i.cxx | 69 +- src/SMESH_I/SMESH_Group_i.hxx | 10 +- src/SMESH_I/SMESH_Hypothesis_i.cxx | 13 + src/SMESH_I/SMESH_Hypothesis_i.hxx | 3 +- src/SMESH_I/SMESH_MEDFamily_i.cxx | 14 +- src/SMESH_I/SMESH_MEDFamily_i.hxx | 8 +- src/SMESH_I/SMESH_MEDMesh_i.cxx | 24 +- src/SMESH_I/SMESH_MEDMesh_i.hxx | 20 +- src/SMESH_I/SMESH_MEDSupport_i.cxx | 10 +- src/SMESH_I/SMESH_MEDSupport_i.hxx | 8 +- src/SMESH_I/SMESH_Measurements_i.cxx | 259 + src/SMESH_I/SMESH_Measurements_i.hxx | 63 + src/SMESH_I/SMESH_MeshEditor_i.cxx | 826 +- src/SMESH_I/SMESH_MeshEditor_i.hxx | 79 +- src/SMESH_I/SMESH_Mesh_i.cxx | 158 +- src/SMESH_I/SMESH_Mesh_i.hxx | 112 +- src/SMESH_I/SMESH_Pattern_i.cxx | 9 +- src/SMESH_I/SMESH_PythonDump.hxx | 9 +- src/SMESH_I/SMESH_subMesh_i.cxx | 43 + src/SMESH_I/SMESH_subMesh_i.hxx | 17 +- src/SMESH_PY/Makefile.am | 25 + src/SMESH_PY/__init__.py | 1 + src/SMESH_PY/smeshstudytools.py | 71 + src/SMESH_SWIG/SMESH_BelongToGeom.py | 1 + src/SMESH_SWIG/SMESH_GroupLyingOnGeom.py | 1 + src/SMESH_SWIG/SMESH_Nut.py | 2 +- src/SMESH_SWIG/SMESH_controls.py | 12 + src/SMESH_SWIG/smeshDC.py | 649 +- src/StdMeshers/Makefile.am | 10 +- .../StdMeshers_CompositeSegment_1D.hxx | 1 - src/StdMeshers/StdMeshers_FaceSide.cxx | 9 +- src/StdMeshers/StdMeshers_HexaFromSkin_3D.cxx | 58 +- src/StdMeshers/StdMeshers_ImportSource.cxx | 443 + src/StdMeshers/StdMeshers_ImportSource.hxx | 97 + src/StdMeshers/StdMeshers_Import_1D.cxx | 959 ++ src/StdMeshers/StdMeshers_Import_1D.hxx | 81 + src/StdMeshers/StdMeshers_Import_1D2D.cxx | 643 + src/StdMeshers/StdMeshers_Import_1D2D.hxx | 60 + src/StdMeshers/StdMeshers_Penta_3D.cxx | 14 +- src/StdMeshers/StdMeshers_ProjectionUtils.cxx | 194 +- src/StdMeshers/StdMeshers_Propagation.cxx | 8 +- .../StdMeshers_QuadToTriaAdaptor.cxx | 852 +- .../StdMeshers_QuadToTriaAdaptor.hxx | 42 +- .../StdMeshers_QuadrangleParams.cxx | 57 +- .../StdMeshers_QuadrangleParams.hxx | 29 +- src/StdMeshers/StdMeshers_Quadrangle_2D.cxx | 1908 ++- src/StdMeshers/StdMeshers_Quadrangle_2D.hxx | 11 +- .../StdMeshers_RadialQuadrangle_1D2D.cxx | 31 +- src/StdMeshers/StdMeshers_Regular_1D.cxx | 61 +- src/StdMeshersGUI/Makefile.am | 10 +- .../StdMeshersGUI_NbSegmentsCreator.h | 2 +- .../StdMeshersGUI_ObjectReferenceParamWdg.cxx | 70 +- .../StdMeshersGUI_ObjectReferenceParamWdg.h | 24 +- .../StdMeshersGUI_QuadrangleParamWdg.cxx | 100 + .../StdMeshersGUI_QuadrangleParamWdg.h | 49 + .../StdMeshersGUI_StdHypothesisCreator.cxx | 233 +- .../StdMeshersGUI_SubShapeSelectorWdg.cxx | 36 +- .../StdMeshersGUI_SubShapeSelectorWdg.h | 3 + src/StdMeshersGUI/StdMeshers_images.ts | 35 +- src/StdMeshersGUI/StdMeshers_msg_en.ts | 793 +- src/StdMeshersGUI/StdMeshers_msg_fr.ts | 385 + src/StdMeshers_I/Makefile.am | 12 +- .../StdMeshers_Deflection1D_i.cxx | 1 - .../StdMeshers_ImportSource1D_i.cxx | 280 + .../StdMeshers_ImportSource1D_i.hxx | 74 + .../StdMeshers_ImportSource2D_i.cxx | 280 + .../StdMeshers_ImportSource2D_i.hxx | 74 + src/StdMeshers_I/StdMeshers_Import_1D2D_i.cxx | 67 + src/StdMeshers_I/StdMeshers_Import_1D2D_i.hxx | 53 + src/StdMeshers_I/StdMeshers_Import_1D_i.cxx | 85 + src/StdMeshers_I/StdMeshers_Import_1D_i.hxx | 54 + .../StdMeshers_ProjectionSource1D_i.hxx | 1 - .../StdMeshers_QuadrangleParams_i.cxx | 80 +- .../StdMeshers_QuadrangleParams_i.hxx | 27 +- .../StdMeshers_RadialQuadrangle_1D2D_i.cxx | 1 - .../StdMeshers_RadialQuadrangle_1D2D_i.hxx | 2 - src/StdMeshers_I/StdMeshers_Regular_1D_i.cxx | 1 - src/StdMeshers_I/StdMeshers_Regular_1D_i.hxx | 1 - src/StdMeshers_I/StdMeshers_i.cxx | 12 + 329 files changed, 34042 insertions(+), 10076 deletions(-) create mode 100644 doc/docutils/Makefile.am create mode 100644 doc/docutils/conf.py create mode 100644 doc/docutils/docapi.rst create mode 100644 doc/docutils/index.rst create mode 100644 doc/docutils/overview.rst create mode 100644 doc/salome/gui/SMESH/images/2d_from_3d_dlg.png create mode 100644 doc/salome/gui/SMESH/images/2d_from_3d_ico.png create mode 100644 doc/salome/gui/SMESH/images/bnd_box.png create mode 100644 doc/salome/gui/SMESH/images/bnd_box_preview.png create mode 100644 doc/salome/gui/SMESH/images/duplicate01.png create mode 100644 doc/salome/gui/SMESH/images/duplicate02.png create mode 100644 doc/salome/gui/SMESH/images/duplicate_nodes.png create mode 100644 doc/salome/gui/SMESH/images/elem_info.png create mode 100644 doc/salome/gui/SMESH/images/formula5.png create mode 100644 doc/salome/gui/SMESH/images/hyp_source_edges.png create mode 100644 doc/salome/gui/SMESH/images/hyp_source_faces.png create mode 100644 doc/salome/gui/SMESH/images/hypo_quad_params_dialog.png create mode 100755 doc/salome/gui/SMESH/images/image42.png create mode 100755 doc/salome/gui/SMESH/images/image43.png create mode 100755 doc/salome/gui/SMESH/images/max_element_length_2d.png create mode 100755 doc/salome/gui/SMESH/images/max_element_length_3d.png create mode 100644 doc/salome/gui/SMESH/images/min_distance.png create mode 100644 doc/salome/gui/SMESH/images/min_distance_preview.png delete mode 100644 doc/salome/gui/SMESH/images/netgen2d.png create mode 100644 doc/salome/gui/SMESH/images/netgen2d3d.png create mode 100644 doc/salome/gui/SMESH/images/netgen2d3d_simple.png create mode 100644 doc/salome/gui/SMESH/images/netgen3d_local_size.png delete mode 100644 doc/salome/gui/SMESH/images/netgen3d_simple.png create mode 100644 doc/salome/gui/SMESH/images/remove_nodes_icon.png create mode 100644 doc/salome/gui/SMESH/images/remove_orphan_nodes_icon.png create mode 100644 doc/salome/gui/SMESH/images/removeorphannodes.png create mode 100644 doc/salome/gui/SMESH/input/about_filters.doc create mode 100644 doc/salome/gui/SMESH/input/double_nodes_page.doc create mode 100644 doc/salome/gui/SMESH/input/max_element_length_2d.doc create mode 100644 doc/salome/gui/SMESH/input/max_element_length_3d.doc create mode 100644 doc/salome/gui/SMESH/input/measurements.doc delete mode 100644 doc/salome/gui/SMESH/input/moving_nodes.doc create mode 100644 doc/salome/gui/SMESH/input/smeshpypkg.doc create mode 100755 doc/salome/gui/SMESH/input/tui_filters.doc create mode 100644 doc/salome/gui/SMESH/input/tui_measurements.doc create mode 100644 doc/salome/gui/SMESH/input/use_existing_algos.doc create mode 100644 idl/SMESH_Measurements.idl create mode 100755 resources/mesh_bounding_box.png create mode 100644 resources/mesh_duplicate_nodes.png create mode 100644 resources/mesh_duplicate_nodes_with_elem.png create mode 100644 resources/mesh_elem_info.png create mode 100755 resources/mesh_max_element_length_2d.png create mode 100755 resources/mesh_max_element_length_3d.png create mode 100755 resources/mesh_min_dist.png create mode 100644 resources/mesh_quadrangle_quadpref.png create mode 100644 resources/mesh_quadrangle_quadpref_reversed.png create mode 100644 resources/mesh_quadrangle_reduced.png create mode 100644 resources/mesh_quadrangle_standard.png create mode 100644 resources/mesh_quadrangle_triapref.png create mode 100644 resources/mesh_rem_orphan_nodes.png create mode 100644 src/OBJECT/SMESH_ScalarBarActor.cxx create mode 100644 src/OBJECT/SMESH_ScalarBarActor.h create mode 100644 src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx create mode 100644 src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.h create mode 100644 src/SMESHGUI/SMESHGUI_Measurements.cxx create mode 100644 src/SMESHGUI/SMESHGUI_Measurements.h rename src/SMESHGUI/{SMESHGUI_EditMeshDlg.cxx => SMESHGUI_MergeDlg.cxx} (90%) rename src/SMESHGUI/{SMESHGUI_EditMeshDlg.h => SMESHGUI_MergeDlg.h} (91%) create mode 100644 src/SMESHGUI/SMESHGUI_MeshInfo.cxx create mode 100644 src/SMESHGUI/SMESHGUI_MeshInfo.h create mode 100755 src/SMESHGUI/SMESH_msg_fr.ts create mode 100644 src/SMESH_I/SMESH_Measurements_i.cxx create mode 100644 src/SMESH_I/SMESH_Measurements_i.hxx create mode 100644 src/SMESH_PY/Makefile.am create mode 100644 src/SMESH_PY/__init__.py create mode 100644 src/SMESH_PY/smeshstudytools.py create mode 100644 src/StdMeshers/StdMeshers_ImportSource.cxx create mode 100644 src/StdMeshers/StdMeshers_ImportSource.hxx create mode 100644 src/StdMeshers/StdMeshers_Import_1D.cxx create mode 100644 src/StdMeshers/StdMeshers_Import_1D.hxx create mode 100644 src/StdMeshers/StdMeshers_Import_1D2D.cxx create mode 100644 src/StdMeshers/StdMeshers_Import_1D2D.hxx create mode 100644 src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.cxx create mode 100644 src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.h create mode 100755 src/StdMeshersGUI/StdMeshers_msg_fr.ts create mode 100644 src/StdMeshers_I/StdMeshers_ImportSource1D_i.cxx create mode 100644 src/StdMeshers_I/StdMeshers_ImportSource1D_i.hxx create mode 100644 src/StdMeshers_I/StdMeshers_ImportSource2D_i.cxx create mode 100644 src/StdMeshers_I/StdMeshers_ImportSource2D_i.hxx create mode 100644 src/StdMeshers_I/StdMeshers_Import_1D2D_i.cxx create mode 100644 src/StdMeshers_I/StdMeshers_Import_1D2D_i.hxx create mode 100644 src/StdMeshers_I/StdMeshers_Import_1D_i.cxx create mode 100644 src/StdMeshers_I/StdMeshers_Import_1D_i.hxx diff --git a/clean_configure b/clean_configure index 366520874..05e43a7ff 100755 --- a/clean_configure +++ b/clean_configure @@ -28,6 +28,6 @@ find bin -name Makefile.in | xargs rm -f find doc -name Makefile.in | xargs rm -f find idl -name Makefile.in | xargs rm -f find resources -name Makefile.in | xargs rm -f -find salome_adm -name Makefile.in | xargs rm -f +find adm_local -name Makefile.in | xargs rm -f find src -name Makefile.in | xargs rm -f rm -f Makefile.in diff --git a/configure.ac b/configure.ac index aeb288943..7b39b99c8 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,7 @@ # Modified by : Alexander BORODIN (OCN) - autotools usage # Created from configure.in.base # -AC_INIT([Salome2 Project SMESH module], [6.1.0], [webmaster.salome@opencascade.com], [SalomeSMESH]) +AC_INIT([Salome2 Project SMESH module], [6.2.0], [webmaster.salome@opencascade.com], [SalomeSMESH]) AC_CONFIG_AUX_DIR(adm_local/unix/config_files) AC_CANONICAL_HOST AC_CANONICAL_TARGET @@ -355,6 +355,13 @@ echo CHECK_HTML_GENERATORS +echo +echo --------------------------------------------- +echo testing sphinx +echo --------------------------------------------- +echo +CHECK_SPHINX + echo echo --------------------------------------------- echo Testing Kernel @@ -390,11 +397,11 @@ echo echo Configure if test "${gui_ok}" = "yes"; then - variables="cc_ok fortran_ok boost_ok lex_yacc_ok python_ok swig_ok threads_ok OpenGL_ok qt_ok vtk_ok hdf5_ok omniORB_ok occ_ok doxygen_ok graphviz_ok qwt_ok Kernel_ok Geom_ok Med_ok gui_ok" + variables="cc_ok fortran_ok boost_ok lex_yacc_ok python_ok swig_ok threads_ok OpenGL_ok qt_ok vtk_ok hdf5_ok omniORB_ok occ_ok doxygen_ok graphviz_ok sphinx_ok qwt_ok Kernel_ok Geom_ok Med_ok gui_ok" elif test "${SalomeGUI_need}" != "no"; then - variables="cc_ok fortran_ok boost_ok lex_yacc_ok python_ok swig_ok threads_ok hdf5_ok omniORB_ok occ_ok doxygen_ok graphviz_ok Kernel_ok Geom_ok Med_ok gui_ok" + variables="cc_ok fortran_ok boost_ok lex_yacc_ok python_ok swig_ok threads_ok hdf5_ok omniORB_ok occ_ok doxygen_ok graphviz_ok sphinx_ok Kernel_ok Geom_ok Med_ok gui_ok" else - variables="cc_ok fortran_ok boost_ok lex_yacc_ok python_ok swig_ok threads_ok hdf5_ok omniORB_ok occ_ok doxygen_ok graphviz_ok Kernel_ok Geom_ok Med_ok" + variables="cc_ok fortran_ok boost_ok lex_yacc_ok python_ok swig_ok threads_ok hdf5_ok omniORB_ok occ_ok doxygen_ok graphviz_ok sphinx_ok Kernel_ok Geom_ok Med_ok" fi for var in $variables @@ -435,6 +442,19 @@ echo # chmod +x ./bin/salome/*; \ #]) +AC_CONFIG_COMMANDS([hack_libtool],[ +sed -i "s%^CC=\"\(.*\)\"%hack_libtool (){ \n\ + if test \"\$(echo \$[@] | grep -E '\\\-L/usr/lib(/../lib)?(64)? ')\" == \"\" \n\ + then\n\ + cmd=\"\1 \$[@]\"\n\ + else\n\ + cmd=\"\1 \"\`echo \$[@] | sed -r -e 's|(.*)-L/usr/lib(/../lib)?(64)? (.*)|\\\1\\\4 -L/usr/lib\\\3|g'\`\n\ + fi\n\ + \$cmd\n\ +}\n\ +CC=\"hack_libtool\"%g" libtool +],[]) + # This list is initiated using autoscan and must be updated manually # when adding a new file .in to manage. When you execute # autoscan, the Makefile list is generated in the output file configure.scan. @@ -448,6 +468,7 @@ AC_OUTPUT([ \ bin/Makefile \ SMESH_version.h \ doc/Makefile \ + doc/docutils/Makefile \ doc/salome/Makefile \ doc/salome/gui/Makefile \ doc/salome/gui/SMESH/Makefile \ @@ -479,6 +500,7 @@ AC_OUTPUT([ \ src/StdMeshers/Makefile \ src/StdMeshersGUI/Makefile \ src/StdMeshers_I/Makefile \ + src/SMESH_PY/Makefile \ resources/Makefile \ resources/SMESHCatalog.xml \ idl/Makefile \ diff --git a/doc/Makefile.am b/doc/Makefile.am index f40fb81a5..6cf4c8ea2 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -24,7 +24,7 @@ # $Header$ # source path # -SUBDIRS = salome +SUBDIRS = salome docutils usr_docs: (cd salome && $(MAKE) $(AM_MAKEFLAGS) usr_docs) diff --git a/doc/docutils/Makefile.am b/doc/docutils/Makefile.am new file mode 100644 index 000000000..a757dd6f7 --- /dev/null +++ b/doc/docutils/Makefile.am @@ -0,0 +1,91 @@ +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +# +# Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com + +include $(top_srcdir)/adm_local/unix/make_common_starter.am + +pydocdir = $(docdir)/tui/SMESH/docutils + +.PHONY : latex + +if SPHINX_IS_OK + +html/index.html:$(RSTFILES) + make htm + +endif + +SPHINXOPTS = +SOURCEDIR = $(srcdir) +SPHINXBUILD = sphinx-build +PAPEROPT_a4 = -D latex_paper_size=a4 +ALLSPHINXOPTS = -d doctrees $(PAPEROPT_a4) $(SPHINXOPTS) $(SOURCEDIR) + +SPHINX_PYTHONPATH = $(prefix)/lib/python$(PYTHON_VERSION)/site-packages/salome:$(prefix)/lib64/python$(PYTHON_VERSION)/site-packages/salome:$(KERNEL_ROOT_DIR)/bin/salome:$(KERNEL_ROOT_DIR)/lib/python$(PYTHON_VERSION)/site-packages/salome:$(KERNEL_ROOT_DIR)/lib64/python$(PYTHON_VERSION)/site-packages/salome:$(OMNIORB_ROOT)/lib/python$(PYTHON_VERSION)/site-packages:$(OMNIORB_ROOT)/lib64/python$(PYTHON_VERSION)/site-packages + +SPHINX_LD_LIBRARY_PATH = $(KERNEL_ROOT_DIR)/lib/salome:$(OMNIORB_ROOT)/lib + +htm: + mkdir -p html doctrees + PYTHONPATH=$(SPHINX_PYTHONPATH):${PYTHONPATH}; \ + LD_LIBRARY_PATH=$(SPHINX_LD_LIBRARY_PATH):${LD_LIBRARY_PATH}; \ + $(SPHINXBUILD) -W -b html $(ALLSPHINXOPTS) html + @echo + @echo "Build finished. The HTML pages are in html." + +latex: + mkdir -p latex doctrees + PYTHONPATH=$(SPHINX_PYTHONPATH):${PYTHONPATH}; \ + LD_LIBRARY_PATH=$(SPHINX_LD_LIBRARY_PATH):${LD_LIBRARY_PATH}; \ + $(SPHINXBUILD) -W -b latex $(ALLSPHINXOPTS) latex + @echo + @echo "Build finished; the LaTeX files are in latex." + @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ + "run these through (pdf)latex." + +html: + mkdir -p $@ + +RSTFILES= \ + index.rst \ + overview.rst \ + docapi.rst + +EXTRA_DIST+= $(RSTFILES) + +EXTRA_DIST+= \ + conf.py + +install-data-local: html/index.html + test -z $(pydocdir) || mkdir -p $(DESTDIR)$(pydocdir) + if test -d "html"; then b=; else b="$(srcdir)/"; fi; \ + cp -rf $$b"html"/* $(pydocdir) ; \ + if test -f $$b"latex"/smeshpy.pdf; then cp -f $$b"latex"/smeshpy.pdf $(pydocdir) ; fi; + +uninstall-local: + -test -d $(pydocdir) && chmod -R +w $(pydocdir) && rm -rf $(pydocdir)/* + +clean-local: + -rm -rf html latex doctrees + if test -d "html"; then rm -rf html ; fi + +disthook : + -test -d html && cp -Rp html $(distdir) diff --git a/doc/docutils/conf.py b/doc/docutils/conf.py new file mode 100644 index 000000000..84a74a570 --- /dev/null +++ b/doc/docutils/conf.py @@ -0,0 +1,200 @@ +# -*- coding: iso-8859-1 -*- +# +# yacs documentation build configuration file, created by +# sphinx-quickstart on Fri Aug 29 09:57:25 2008. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# The contents of this file are pickled, so don't put values in the namespace +# that aren't pickleable (module imports are okay, they're removed automatically). +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If your extensions are in another directory, add it here. If the directory +# is relative to the documentation root, use os.path.abspath to make it +# absolute, like shown here. +#sys.path.append(os.path.abspath('.')) + +# General configuration +# --------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc'] + +# Uncomment the following line to build the links with Python documentation +# (you might need to set http_proxy environment variable for this to work) +#extensions += ['sphinx.ext.intersphinx'] + +# Intersphinx mapping to add links to modules and objects in the Python +# standard library documentation +intersphinx_mapping = {'http://docs.python.org': None} + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +source_encoding = 'utf-8' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'SMESH python packages' +copyright = '2010 EDF R&D' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '5.1.4' +# The full version, including alpha/beta/rc tags. +release = '5.1.4' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +language = 'en' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = ['.build','ref','images','CVS','.svn'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# Options for HTML output +# ----------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'default' +#html_theme = 'nature' +#html_theme = 'agogo' +#html_theme = 'sphinxdoc' +#html_theme = 'omadoc' + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = ['themes'] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +html_use_modindex = False + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, the reST sources are included in the HTML build as _sources/. +html_copy_source = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'smeshpydoc' + + +# Options for LaTeX output +# ------------------------ + +# The paper size ('letter' or 'a4'). +latex_paper_size = 'a4' + +# The font size ('10pt', '11pt' or '12pt'). +latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, document class [howto/manual]). +latex_documents = [ + ('index', 'smeshpy.tex', 'Documentation of the SMESH python packages', 'EDF R\&D', 'manual') +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +latex_logo = '../salome/tui/images/head.png' + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = True + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +latex_use_modindex = False diff --git a/doc/docutils/docapi.rst b/doc/docutils/docapi.rst new file mode 100644 index 000000000..b39c124dc --- /dev/null +++ b/doc/docutils/docapi.rst @@ -0,0 +1,17 @@ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Documentation of the programming interface (API) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +This section describes the python packages and modules of the +``salome.smesh`` python package. The main part is generated from the +code documentation included in source python files. + +:mod:`salome.smesh` -- Package containing the SMESH python utilities +==================================================================== + +:mod:`smeshstudytools` -- Tools to access SMESH objects in the study +-------------------------------------------------------------------- + +.. automodule:: salome.smesh.smeshstudytools + :members: diff --git a/doc/docutils/index.rst b/doc/docutils/index.rst new file mode 100644 index 000000000..fece6eff2 --- /dev/null +++ b/doc/docutils/index.rst @@ -0,0 +1,14 @@ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Documentation of the SMESH python packages +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Main documentation +================== + +.. toctree:: + :maxdepth: 3 + + overview.rst + docapi.rst + diff --git a/doc/docutils/overview.rst b/doc/docutils/overview.rst new file mode 100644 index 000000000..5ab13766a --- /dev/null +++ b/doc/docutils/overview.rst @@ -0,0 +1,24 @@ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +General presentation of the SMESH python package +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +The SMESH python package contains (today) helpser functions to +manipulate mesh elements and interact with this elements. + +Note that these functions either encapsulate the python programming +interface of SMESH core (the CORBA or SWIG interface for example) or +extend existing utilities as the ``smesh.py`` module. + +The functions are distributed in the python package +``salome.smesh``. + +The specification of the programming interface of this package is +detailled in the part :doc:`Documentation of the programming interface +(API)` of this documentation. + +.. note:: + The main package ``salome`` contains other sub-packages that are + distributed with the other SALOME modules. For example, the KERNEL + module provides the python package ``salome.kernel`` and GEOM the + package ``salome.geom``. diff --git a/doc/salome/gui/SMESH/Makefile.am b/doc/salome/gui/SMESH/Makefile.am index 187295302..1bb1e9bee 100755 --- a/doc/salome/gui/SMESH/Makefile.am +++ b/doc/salome/gui/SMESH/Makefile.am @@ -31,42 +31,40 @@ guidoc_DATA = images/head.png usr_docs: doxyfile_py doxyfile - echo "===========================================" ; \ - echo "Generating Python interface documentation"; \ - echo "===========================================" ; \ - $(DOXYGEN) doxyfile_py ; \ - echo "===========================================" ; \ - echo "Replacing smeshDC by smesh" ; \ - echo "===========================================" ; \ - files=`find smeshpy_doc -type f` ; \ - for filen in $${files} ; do \ - sed -e "s/\/smesh/g" -e "s/smesh\.smesh/smesh/g" \ - -e "s/smesh::smesh/smesh/g" $${filen} > $${filen}_ ; \ - mv -f $${filen}_ $${filen} ; \ - done ; \ - echo "===========================================" ; \ - echo "Generating GUI documentation" ; \ - echo "===========================================" ; \ - $(DOXYGEN) doxyfile ; + echo "===========================================" ; \ + echo "Replacing smeshDC by smesh" ; \ + echo "===========================================" ; \ + sed -e "/class smeshDC/d" -e "s/^ *#/#/g" -e "s/^ *def /def /g" \ + -e "s/smeshDC/smesh/g" $(top_srcdir)/src/SMESH_SWIG/smeshDC.py > \ + $(top_builddir)/src/SMESH_SWIG/smesh.py ; \ + echo "===========================================" ; \ + echo "Generating Python interface documentation"; \ + echo "===========================================" ; \ + $(DOXYGEN) doxyfile_py ; \ + echo "===========================================" ; \ + echo "Generating GUI documentation" ; \ + echo "===========================================" ; \ + $(DOXYGEN) doxyfile ; \ + rm -f $(top_builddir)/src/SMESH_SWIG/smesh.py docs: usr_docs clean-local: - @for filen in `find . -maxdepth 1` ; do \ + @for filen in `find . -maxdepth 1` ; do \ case $${filen} in \ ./Makefile | ./doxyfile | ./doxyfile_py ) ;; \ - . | .. ) ;; \ + . | .. | ./static ) ;; \ *) echo "Removing $${filen}" ; rm -rf $${filen} ;; \ esac ; \ done ; install-data-local: usr_docs $(INSTALL) -d $(DESTDIR)$(docdir)/gui/SMESH - @for filen in `find . -maxdepth 1` ; do \ + @for filen in `find . -maxdepth 1` ; do \ case $${filen} in \ ./Makefile | ./doxyfile | ./doxyfile_py ) ;; \ ./doxyfile.bak | ./doxyfile_py.bak ) ;; \ - . | .. ) ;; \ + . | .. | ./static ) ;; \ *) echo "Installing $${filen}" ; cp -rp $${filen} $(DESTDIR)$(docdir)/gui/SMESH ;; \ esac ; \ done ; diff --git a/doc/salome/gui/SMESH/doxyfile.in b/doc/salome/gui/SMESH/doxyfile.in index ce268972f..535cc57c7 100755 --- a/doc/salome/gui/SMESH/doxyfile.in +++ b/doc/salome/gui/SMESH/doxyfile.in @@ -70,3 +70,4 @@ GENERATE_RTF = NO #External reference options #--------------------------------------------------------------------------- TAGFILES = smeshpy_doc.tag=smeshpy_doc +SEARCHENGINE = YES diff --git a/doc/salome/gui/SMESH/doxyfile_py.in b/doc/salome/gui/SMESH/doxyfile_py.in index 6d45aa6b5..6053cdfd0 100755 --- a/doc/salome/gui/SMESH/doxyfile_py.in +++ b/doc/salome/gui/SMESH/doxyfile_py.in @@ -98,8 +98,8 @@ EXAMPLE_RECURSIVE = NO #--------------------------------------------------------------------------- #Input related options #--------------------------------------------------------------------------- -INPUT = @top_srcdir@/src/SMESH_SWIG -FILE_PATTERNS = smeshDC.py +INPUT = @top_builddir@/src/SMESH_SWIG +FILE_PATTERNS = smesh.py IMAGE_PATH = @srcdir@/images RECURSIVE = NO EXAMPLE_PATH = @top_srcdir@/src/SMESH_SWIG @@ -157,3 +157,4 @@ DOT_CLEANUP = YES #External reference options #--------------------------------------------------------------------------- GENERATE_TAGFILE = smeshpy_doc.tag +SEARCHENGINE = YES \ No newline at end of file diff --git a/doc/salome/gui/SMESH/images/2d_from_3d_dlg.png b/doc/salome/gui/SMESH/images/2d_from_3d_dlg.png new file mode 100644 index 0000000000000000000000000000000000000000..a03530978f29caa18e64729480aa02cde20066c0 GIT binary patch literal 21853 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/2d_from_3d_menu.png b/doc/salome/gui/SMESH/images/2d_from_3d_menu.png index ec5117214dacaa84c2c4ef4bfba338d141a7f344..acb7b349e3fb1c24bcbbf4fb695ed8bfebbb23fe 100644 GIT binary patch literal 24838 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 diff --git a/doc/salome/gui/SMESH/images/a-averagelength.png b/doc/salome/gui/SMESH/images/a-averagelength.png index 70e2afd26dd6ed299365193b2073c28946ed0695..c8ca5ac772651c15214eb8396d322187201641dc 100755 GIT binary patch literal 13595 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 literal 13679 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

b@R{rFI3w-&fUGRNK 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

kbrQWH`@(8qoV4DC6`=dUT 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 diff --git a/doc/salome/gui/SMESH/images/bnd_box.png b/doc/salome/gui/SMESH/images/bnd_box.png new file mode 100644 index 0000000000000000000000000000000000000000..6761a76ff1eaa5729b6a473af5cf6772a65a2f72 GIT binary patch literal 17441 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/bnd_box_preview.png b/doc/salome/gui/SMESH/images/bnd_box_preview.png new file mode 100644 index 0000000000000000000000000000000000000000..902101cf35a053647287e8906d6a5d67fc169964 GIT binary patch literal 56083 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�MNla{1Y|k9qTx$1T7x+UKTDlGaag9r1EvuX_HTS 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

$Q%6XfK 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/duplicate02.png b/doc/salome/gui/SMESH/images/duplicate02.png new file mode 100644 index 0000000000000000000000000000000000000000..1b5cfabc519f8a36d467d5f2ece088bdafbc4244 GIT binary patch literal 13187 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�p`p2u_>sfzfl23NGV>kJKj_z;nh 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 DS1}Y3 literal 36255 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 diff --git a/doc/salome/gui/SMESH/images/elem_info.png b/doc/salome/gui/SMESH/images/elem_info.png new file mode 100644 index 0000000000000000000000000000000000000000..9937d6d88586b9f0b8f62db1f680167ffcf779bd GIT binary patch literal 907 zcmV;619bd}P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igi8 z69p{^#?W>E00Rq2L_t(I%dM16Xk1kk$A5R`<$DaRDQ|)rD|QwJDo#74?T{3!bTP?` zn~uQW-qG>>_~>X`Jb*p`Gz`P6t*z}?SQsS| ziJbI2?^dZ)Dpr1C{Hvx;kSzgdF4!X)jfTQumDu}o%UhPU^|jX4dAXO}*E^h^y_+8S zv;W4=e|-bkJfyK3fHupzEWnn^W;7a&9ysvg#reB^;ujB!@AZi9b%~SPEg!u9teB>` zeYM7R06P>i2xbS{yQ`}&aeaD>ufD!aHamk~`h$J1YU=Ab*4WrswVG1w zp`k>3clYFY07b<2zdOJ1_lKvJIex;)9y*-8Id(qJ?b}6W=ZaKS$&yI|ORnp}Bg~-zXzT8ttkhDa zQWpg1d}Z&`mwx+Ym;5^SjJ)^mCW*(JmTPKi4g>X%G6x5+wHAP8%bF->GJ9f%VQgw? zsf&sf`RRt{+&Qu{GfuzfdEWw_v4%A5vuC%rTh_$5)*e8!*4n#zHD5S!(j}WMGdriR z=kxBTz$~EGvM&d)MKqbro<1OE7{*dE8B!me4s-mN;Ijm`$!Q2OAnwpxPDwRraXsw^uTL0*}?kB*##{s?s h^aOex2z39@xDUtgVtTen16BY4002ovPDHLkV1klprFZ}U literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/eleminfo1.png b/doc/salome/gui/SMESH/images/eleminfo1.png index a93a622f1d44046971ac167d2f52e5ff7cfefed3..4d12b54b1279934a85b3277a9e47b437f4b2e313 100755 GIT binary patch literal 19088 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 LRrvzh2mb#LB6Je| diff --git a/doc/salome/gui/SMESH/images/eleminfo2.png b/doc/salome/gui/SMESH/images/eleminfo2.png index c417b6d25f37a6a14349ba792d770376fee7f1b0..26cfae3651dabdc316df9acb76f1f47c05314fe8 100755 GIT binary patch literal 36810 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 z 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 literal 33198 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 O09f1T&Rb3U$o~SkVZ?I) literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/hexotic_parameters.png b/doc/salome/gui/SMESH/images/hexotic_parameters.png index c06ff3bb2ecb0a5ee2f3ed61570aa8a481d7d9de..5f4bb3df5e8f7ada557f671ecb1a37fa7f0eae30 100644 GIT binary patch literal 23172 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

Ro91sV62BNF+gcmRQ`l zS(+i?ONiQ!47%_wWF0GjN#t%+BsM%~v9FCr-=Io|^{4$Hvwq@CD~K7&#JKx2Jhxz!Jn3&36fX!j8HQiy=cDBZ=2w8w z;GWpoT_wu!^6_;)tS>2H!CccUP%3)6s$0$9$|6ULOA$Yip|R^O0n7wEj0p z!~Ad$w#(}i6%j!dhuooD*<4@06B%h&*iaqR?7y=PT|8ZZpkGrdc85|9xsOyY8g8CR zo~yQysiJhIc2&SbvQYM%Hb2QiNB3sdD`m&KV{kC#*!>1tB(8oDc-FgYt+b0iW;S4XF_s}rEyvfZSfitEW(`8K#mk^2RtHXqG^ z8sXs*_xv*~8K6LiG98u^puNCyk|WTlB_rzB%JN}e-ZM6Shg5^mb3JLAJSI?+wJeX z0TM0ikK_K<2Osuf-GaqJx4C^*Y%=ZJphk8!_v$v*qXF_4(P@^x?yYp@<>STxSXIj0bZg zA|fntuOGI0)cRg1HO#ve*gp@ywY9P7VO|&_>Xr=V73xJr-RtOX|90GGXu%<3FHpaV zq`cBn%u-M#t11)>9)W~W9j|G9TzWQv-`(;bZ>Vz0BdZ0v!WHGL9Chw~Fsh`-)c zbtS91C~Aq0!w>bbLcZ5U(YC(~W4C_EgYi|G!tz0ZiWkjFw!C+G8iqCFx^dHVg z!}! zQCnl!A$shrd9ftN*1~=Sxm`=4%7`GM|9O;OsS)zI3!gS-gbZ3Bhy;C47UC00c literal 21710 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 diff --git a/doc/salome/gui/SMESH/images/hyp_source_edges.png b/doc/salome/gui/SMESH/images/hyp_source_edges.png new file mode 100644 index 0000000000000000000000000000000000000000..2305e178bd6c84cfe60d537a90741ec483eb22f3 GIT binary patch literal 13394 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�WkOa`S`f@*wXh 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/hypo_quad_params_dialog.png b/doc/salome/gui/SMESH/images/hypo_quad_params_dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..3cd442a8d4317a1b4defb0151b3ff6ded3b00dcb GIT binary patch literal 21190 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/image43.png b/doc/salome/gui/SMESH/images/image43.png new file mode 100755 index 0000000000000000000000000000000000000000..7b6b895a1d83a5d1393a3af60c2a8fbe4a7c0433 GIT binary patch literal 965 zcmV;$13LVPP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZq>)?Vof(C zC13~yM`(&}M6`?8O1r2b5?W%XNEbp2VxZt!QX&$v4B03F#ejC@!laF5bcQ5;kQp+R z(#*Vj-+OcKJucqIq$PIcfy@7LIsDJp|6ET*_&+TN;CbF-kF&G0S(LfCIqzu%larIu zYPIlvpVie>FL#(zS63JLe4cu}&I5TzzyShu0U#J4L{NP6uBNxQmqw!jFp&GN$h*6{ z7-RVJ*QJ<5!1H1h0c+#4zkh~Wt%flM;7w0N9xM5QyeI$M{RZd2xeh^UBJsPm!iysV z{PshcBgc>OTHnJpU_A#gH8myO-Q9Se$KM-YWMl^kQ_@?v&Ju{>!VhyadhZ((jScwB>l2U524i>pin4KsZ>y^iPnlh15gJxasW{jv9q&- zbB^s_zRgNHtYoF$pi-$|ttAXKQ50a>oeaAGs?{o=&zHG$=_{OrD_6#{UX@B?T)P$@ zYlZ9Azr#7l`1m-+v~kYz@!97)3IQ<2aQb9~2ux3pptVkjM;IL)<>t*bZru2hnVFM_ zIFwR^VTf}U=WIIRj# zn0~*Pp`oFfEW_BbjdPO7#SsKL>(#`>XNWj1Uw$2>nwh^+O{}$~96%uxc3obPKYqH0 zF%GR;Xzde4ai2WT!#Rhw24f=nj*U~kvqThyEG~YUt?TCIW+_`eLDOzqe19LMngl^i zDB_Y0k&LjpFKF#^R=lwkGA!2b>aM@J*Ey`lN)00000NkvXXu0mjfoe{Pk literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/image49.png b/doc/salome/gui/SMESH/images/image49.png index 74926d24450a3e5b4ca4e9466d88538874a38df9..6e5b3176bc67ae89e0b55398dff8f90a58084dae 100755 GIT binary patch literal 988 zcmV<210(#2P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igi8 z69ouD!UQn@00Ue}L_t(I%dM1MXj^3%$A9N^tu$S;m6~Op7gE=PlYtqVUUW{%TAh>0 zDvN6`EW2juLyw&{NJ2(!gswzy=WNd6q`cFX1vS@05jTdx1IWRC#1E44hx+Rc+ zr;dD71hE=N2bm;QCjnxZ$4X(X_~u%?XoQQG&R*S^vMo< zJ{yD%7?@U?$omP7y^(2ARrRZ-3g_qNQFR+tw^`I}vWCO+kqLki;QYpoYeru=T0vRa z1ukDY%kY;MQIuaOl9+73aY6&|1+tooscYoToSUx$dbaKB zhaY?w>T-Yd?GtQXrG)=dJQo20kQ z-UU_zJ;gW-JW_m5NRsqpI&If~aYC$3rtFeMRb*D2!5dl*0Q-vVjutP^uHpyNz-e{ zoe03eIsc!brrG-X`lhBP)2+O`yl6BUjYe03ns(aQ*x1m}keVlyO-xLlIeiL1RaKSE zWWii!)9b4jq=hB)rd>)uyMP8QdK1+c!R+JlUo* zTgmqAr_R2&_uQvie_d+l0auppFKRJ>tcp`vPss<$fYT!t&%?eQpzGCn@;^Z5ip zSR$W;n=YMVYQ_DYPypx~SnLMWxnAP%$PFL>J9BJU_crYC(W znbF@J@9&O3x%WO462c(?Kt)uVKRyj<%OKW+V#qC(0OXbez)V8@&>Qb)`PAE|XBFg^ zl;;`@0Qh43mZt_qtW#DE#5(0zr|k5IIi86pXVtBJb7cX^6r8DNb%HyDmq~cb8XBH!Ykv*^=*aN8$_|EB6=msw=$r>GNL~uH{-TP!W9v>- z*oWom1k+ZBeCh{VND{|hW8@`^5M+yoHh6aZ;U0VT~?o78k?5Uon nO~xlzDEqVcCqKUb{4wzZCeiR|q-K9=00000NkvXXu0mjfJ-v_Y diff --git a/doc/salome/gui/SMESH/images/image79.jpg b/doc/salome/gui/SMESH/images/image79.jpg index 6d164167fb70656b96bdf17c574eb4ed3765009c..0efc736950fdfe0da08551e01812327ecde6a5f0 100755 GIT binary patch literal 57934 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 literal 49431 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%0DsClS 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 diff --git a/doc/salome/gui/SMESH/images/image99.gif b/doc/salome/gui/SMESH/images/image99.gif index 4959ed82548939a522238bb5b9c57adb0d1dfb6d..2672e99f3241466518910e294744154285d7cc9b 100755 GIT binary patch literal 15691 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 C$i&J3 literal 10733 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 diff --git a/doc/salome/gui/SMESH/images/max_element_length_2d.png b/doc/salome/gui/SMESH/images/max_element_length_2d.png new file mode 100755 index 0000000000000000000000000000000000000000..012d552f5d47417cc07d89c8f2c1450622cdfe2d GIT binary patch literal 18345 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 CR{D4V literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/mergenodes.png b/doc/salome/gui/SMESH/images/mergenodes.png index 024bc22e85cb1695b57f221f137c7c921952af37..54cb3d17adcd6a78de4edc0cf0eb66aa0ef38886 100755 GIT binary patch literal 35421 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 E0MSAAIsgCw literal 36395 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

QjtXcFFS-mSs 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

&fL2~Loak&)C=?j9Z| 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 Q+942{s=6v~m2N%!7u>Et`v3p{ literal 18806 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 diff --git a/doc/salome/gui/SMESH/images/meshtopass.png b/doc/salome/gui/SMESH/images/meshtopass.png index 9a5c62e245c15881a3195183d3c967a2fc143714..1c426783e94d591b1e8a11f91afa51d28bf623fc 100755 GIT binary patch literal 17937 zcmb`v1z43`zbCwDq(KQu2|)n?>FyQ*>F#dn?h*+B0g-Olw3Kv9Nw>5}w{-4V_&o19 z@67eg%=zYgUfT=Y``&l1_5c5B`A$(@3KNYO4FZ8+%1DbVK_GCG;BO)-GI)o{L8!saB*=cxbweZ0{Df5{O z;&2Fyqt9JGY;C(v(fHPmU0^qm#mc+~ay-Wl zky&ziVHy=e#66w#5DJB6yXXsOo!7r~zr;gcz=+F*wl?i8Ofj);RUUJ zO!E-aiu(H6Ffjcz{D|q&V#(m!n9@0VBDeX6nc#z{{dO~RlK^A(|VW@cm^Z54urx8aEVRsFce- z?mnk9V{?w}4N95t5;}!6Rx~pQB?upJenRo5Y@@U3y988!FkUf>VORxIs7YXb#b6dX?y1_e!<4VQE6<)F*=k)5sfJ z3~+ZcWwj}X6GzW?T2g=K%{^V7LsSvlM+$nM*D_Q>qKvMWF>dwd^c68pZ=LzN%(HiL zJmbRrvDa{-s*^6$@zVAKdqri=Ys`uhldYDhE|1J)B%CcC^$&8JRMjlU-OoEwnLHda zvY_IjfcE!EA7t|(Jm(!Wl!$SC>@23@k$v5IJUU?Q) zsZWG4heC4v3u7~B;y*lnFsQ&`K2_!avMM|96rbZ2Lg~!abA39>C8l=9l-P7k$@;14 zT*epMGPy~j>KA1P3>@PS4EV7r&zV-$ET~N3xEX3^f0$o=fow_$6l&qO!zj**wOSof zJ&Ne!xy8Q{6FSl~jCtV8?8%JPuARXnPTWF@j8S#$&5yR^i>-rQ4>1w7v9LhxJNOKz z3MTKfA1TBmo)!2D8&v*q74}uxm$3^LLM{Z)e!3(b)M(n=UM&C zu~<0JR7xZO54Q8C@Sxk;!Tf4=*_|$L7%sH^0VDk&AHj z*hRbCf`FMQZe*q~%Gb}Or?uXf9}sU7-dQ}7G#QH0^K7JZIz3oJop*^&{Zd^>7rRIh zYL@jrX?-5vz|71{a-3wF&u_lh3#K#~-x3Yi7O^BU$QAQR$v|$H0`E1+YehocuhbJX zkxOPnmievLL*!_B++jTB=2aIX*)wZ|eKKT}HEgSx|GM@^@ELzf37AWGjVZ zOR)S7Yi}AyTX_9I!?RuKmnEfQ+TcWux`nQd0`~|Y&;wgin!B)pPjY;z%A)q1Y zunRSKiS;jhP_*^R@)7ebhz4(_-U@lD`-5M!e$~IGWTt*XMMdB5yniY-ul$sXY7A8@ z0rWp=3{@&Bswftfcj4je9g6>NAM}Raq+7iVqzm#aZLp~!vmS3m6Bn<>dWt=Hamp=9 zD0;Ymp6EGg%IwbCYw(l`YVZ_ObuB+|Bn0Pkx()rBl}n}5v^)mP)LnIeU0}BB?@cBH zoDeK{W&+9F4usXs37cXz_DivRxP!%7#J--*)+ni2ccNBaQFz<)%yis;Me!;6<{sjKW(cY zc+j(ebrEwFE9u#H;}m4uhoQ3k3B0e&lVQ((JM^wsct-@*J{j?FwO{UDhh+$s+Xw7`6cxpgxC-k zcJ|;`t*yaF%snd}6G20SeCSigcAmq1w!GXx6L5%SbK2(U?{v_fp)ZNzCH(yA1sTjEYm)hib z0uLFvac2XcMVrt+fS|%&My7Llei_*Fa2SSeQzhr_!bDLG8oqima`_y&medNO4FtW705dBY7jqPoi;@^7fPUAO!M; zdfB%(YUJ`edB%nzw)pFH#j^UT$X6?`J`5IPUwNxRdmP7|67|h})|s@%prh}?Ez-fG zU)7JcR#KC}hC#>aCoDNOV7(dCUr)kbc@%h@dEmG|g_tS@#3_#4Ir8ye^UrR*R^ZG! zSP(pEoO2lFD0C^yBexx{5n+{?sj|jCYdG)lDd#i4RGl_= z-4vJ{5C)U#3Bc0H$;kn~CwD1db#B{hKum@}|8r+`XAMsbdSOlP#m0L*q=`(A`{qH( z&f&ps>|k#KDi*&_VYQnI_+<9=+xH!(#N1qM_j?ltQ?#BzLsj(!|1m8=1CCK99C;<1whK1lQ%it_f7jtp{OCJ<%D!TBdk^D{y54U(>2gkz3#)hy~>~0n*Qd0Cp zGcoH~gewO_+m^GDiAk=>4mDNww#l4b=S9-0wYEF&G093S11_oimEzid5fg@rsw!?P zc^Gd^3x)7TIykLTsqWD24v2~!y@j2n7(B|&)_b*A|z-S_;I!iwcIxez$NGFGf zPvtO*x-iM5opV!SP-z#}A6<617(!%eAGlz<<^mVUaNlCw@SWSmsSC z_G@1A>%N;vS;Da$4+1FqQ)1_xt>E|$i>o?#g&j}8h{qi6Bxm;|Nn%WT=#Si{V*LH1 zn<>sZ#s0Uc18qtSdb}g#t%_UGu$QcE<|l+5 z4Q|#X@R*5?B@e+Ahoz%o63sZu zvb(DHzWZgLjtHnYVO_4r(qUE6Q z=PF@}-8YNdLa^(M*|%&kbF*1tq(tntU)7N+vLQ9JPA|u%C~PDgS)(roY2I*ZRJ{8Bl-+y1{?K(C%{LJ-gGsJ&0Bj?qbA{^uFE2Q5jnFl-+ zzh1CrADnl(WT5|aeaM2@)v6dPo1gjF6bv0#Rf$6roOk69ExcMV&l-0j?ot38Xi+SP z;eWz@Jsnimw0hh}=&uwN+(0o!nMIQ+Uo7pD1`qi}^Ke(FI!As2u6Le+8=Q<71$KMm za0;d>nAc!#Xa;YmCWtzN>i~B>RmhR5G~ekPNeHg!FTLBHrs)U9QMi>mFWr~>B3J)h zxR_?hwiP3xzi9YVxQ0(U44ub?DEY(>C$=u%ClVC`m_d$D0^LCqMlfg{$GT2COC9~| z!k@h__M0}^-`0NtV^suYTHxQN`FBS*PI}=)(`T}G`hJuE7OB_naYp*_wA6-}D^N<7 zi90NBi6u1Nk5d)9|JNGxS5*=p*DtEHt+Ui5#l?LiG0LcdFQIvj`3|5hC>L zKW&O$`ZY7u66h&RUT~sP>_=%{1{J2D196vWV3p%fY z(|{v79{)N|$F|$b^UJ$-S#cE+Sz;){2J(nw1rp!>Vl0_Cl%w4x2K~iwb(?R2Zv5%) zS1*(@AJ@|5uZ}PLvOrb;g9hGwQN&Eg=r}K7zINZ=f7PEGc(}%bRZZFkyW4|>t}=zu z?y#X54;hypoK=smG5_+K>bXZ@ki6zA_3v2dcS&`<76S7T(Z*z`Eo7+~QV@Xx&*k~G z;8i=68>w4q>a;Y1#}RFNZ#&m3+SgpOV4^}#)(?bi=IjP;g!o`TVb{awoolY`>lIn; zbN&E!&2E8Hn4&IqnBVgsG!#2#8?E3%n5ZFrU~;6E@#@2OS_$ zFzjbc-Ar205>@jS9dEuaYlP+hrr`i70=)^wf;>mBgZ-OL2ENF-dh*jfrepAtH zl@Qu*bPikRNjTT+$c8wdK7E2fA|djR_V{Wwfxb~P*D5}L$V z!ln53?Hh|AC)PFgF8AG!qwE3fbX2M$nwO+x-yEEYj>>;-3e0MsTqTkGh^~35@h-ey zW7b5el>*3R!jZ^Yov&Y$znZ;G;S?{xUohcDN2Ezl~V3Roda94BkO1|YS zt8y*Qp}{(|k9R#ln4Jlk??^ z+fKZbvn5RuQ+%4-)6ikVeDbPUqDUCRHn@b4X+D# z0n--(2>g)jjPizJC40c$D+@EN+|?+C!Rg`$7;*sY;Wyu{o!mi_0>Iq<_HR`UfS0dr zjwYIVM-C>SbiY8+o>Jk2GhgDlM{++PJG?i1Ub!zFp9Uf*P|)wCZ_m07{U!*pW^u6d zzuy&{ECJL>y`*f->c=3XGiBF3V8eO3pqz%THY{jcHdgBTFKqVw9-FNrb^pO;1ozm? z@E)5L+Sn;egNnKJ->jHPUa%p{6VB~=PmEAx7hNF$_Xu^x@F5NQ2UDiaeJV;xr+Bz; zPJgZdFhv!$*-}7{A$manF=4akO>?ngg3fvUNm<92nRSvN+m_3ZVktZ1P*cUAFVxfh zuQCV`o>cG%`ghrX8@+hAH&oY1?%a+)2J5cHtL2#^h0J-A_2&&fwp_E@m#EFmV+|l!{4S8JV@mehYRlE_ENc8qp?0kn^MDOH@=sQBENIlhINZ0b@~gE6 z3!(4)LW+-6YDsrPrkg2r>TxYfCQAnOp1Q|r+O9uyKorBdwK7sOmjIVu({C4S96X&OF#!h_WH z2*QP*Ykwy8x;yrY6A9E2oMLR-A~n(TBfE=?^NpsgtC*|NGts$k$lE3L3YAV_fyhJH znL7zgz1k+ILBiA4x}eOzttPdZJ#5&d8m7|#F!m~JhcXgg6gB+wcl~&l6`>9o+`u`b zwJ-Iqdp$xLv)g*G6)3QP71vL_(BP=O9D74DyDogUjFFB;RhqaC|GC?i+?y@D?G>E+ zxfdk{Jb*bvH|1e-em`0Sstfo7fJP)BH(IE zQ-h*#Al3fGPnrwI`BOV_p@{5rpg0Tch`}0fSq98N6|0{6l)!j_$bbP4K-O2^Ux6&B z;7RRY&vPGk!x4p4vY$S$k+3zdr>>HEyB4Fart{sX(%@&S8Z6LhaTPpk+FVW z@k+Ey?)ig@ru8?@;mT3lbOiuOj#_)(UhR#4{-{2Z%^BlODx#}PMv8@^RP+e&UhZ)( zU7p;A-T#Q<|jnk&J*y?I-}R`cCY1WQQGR zd&?l!@t&D9$5=xx%b^kkj0{oE0aRTKLkHmkFC-Gyu=Ehiv;H=1xEvF4`UH5p$pTpt z+an~5)zwvNy;==h=Gv^=ZdcG;P}9+Vo}@hWG#(7I)r;fQxA+y0d(t|m|GD$_lE{C; z1P$Di$jC@xR5;l14fij;T>Ui8Pm8uKxX##ck#RC#Fv1whW>2EBx9q>Q6EA zto)z;BEp4e+vG>0i&SEZRK^QSS)34{G;trEz@_dBl1JD!XXdgyOQp>~U zwsse_RmUm^xgzeev=E!F2ej*T&V>CS1?fx zZ(BI3k{aZpP%3x&@bjxBvFqWv6^|~2H#x)8F5vjMx9n)=V#!XvVi_3i01PHIeC+ti z9CF~W`^I$kmRXpPZ6vHO+(7G0^sZupCY3LII3vrVLB412#=w?=HT#vd| zliP)W;WQOgYT;Me?7X2xVCmWPAg$cF7zee9wD1Q5JRIXCqSs!P^~~FItfq5V zGm5E_2z`Pms6n8~_L<-n^*xdlBI~XhE-T#`FK?0Ey>hYxkg^`2ndycOdUtt$-*g63C zgzHz=Mn!%7n1)6(F|{D!J)voARn?V+jI9yygcWJ=gPB98bPVs+fpAFb zAh0aD!!~)1Tr6MwDs&~*5NHJu71a>lJhQueHa{tFu7|x2i)-}wbKa|S^GoYtZmoo6 z*Qc%Kj1W*EAN(eGj1`7J@E)nCNM(IOIRW}@x*jmy?uj-)VsnT?;}oA*nGm%e1pYoJ z`7p@3y~J6Qpz}B7>)M73 zX5GE|l8KQ?R!_xqZu;`$G*(824)sIt)n0espX~`kdVQ&|i9a=+?-(jdj}A z1@F=`P#WG~_`7AGtPJ?();46)8Y$XG8#yRtu4TqKO;ba$La;V;qV&4Sr^&&O7sX;i z)vh+jg9XHMIxxi-Uy#8KZ0RiBgejvQmBVddmlnd_km1EYkgkcN-FQH!6aZv~7{q;1TmxJM1UX2>ia%}i1*x%(n{<;>MT!#v>wx|~Lqe5OTXwB>Q zefiBB6V~MAhG`_jN7B#U?M|E1TQd|s!$0Z!$ld{f0<>cAG$velH z{=2e%_Exi>?VPO^ffU%~8+LS6i8m~FYhTs6fvv7eN`CjxHUW_z7Q(->0DpT4;raSS zno-MrnR>;Gj{x=A(nX@meqHcCb68L12k98BfE3A={5yvwQMwz_<$HOPw1WA(aqMqr zfW9&=bi1t{4s_o3=tj59{dC@@^SN`!{DZ$(tgY@2j%bM`&x>^8 z?@p0cH|`Wj#w`45$gm0!z$-u%!7MtU2QOH%=K;Au`%)E zo?|16tFevh90%9EP0+zYm5ukzvJfrEpT%Ts+#~5BkaahOrZd=l_hHNLp2W%Gb&eWh zNQL3T=%W|on`gHGBK#mn`x4CT;@IMFED5K?1D|5T96yq7lvr$*vst3xm&)t&Cn23( zU5F6CYT+L~d?+z(cm#p;so)uBL}jh!VO{w6(kRP-PM8V)L3+TeS7EcED=$s^fSMx4 zWP|L|9WhP@XnY&cTI-b&*ODk8GE}$!I}tIo-Jn6&bVnTn-~k+>uaD-;^Nfo4o#;gP zt~y zm*M9sVcw=XB#p>@G;rhoYteZz?`K$ajHUR-$6@tTO+Qak*Q^J>K59XnZMv!eqhhC0 zX*OH3?e+r+sI(COzdQ%j4$nGkI|bEZta~~I6#LJ&&XzL6MfdK)tnS(_3>jnruzM6p zhaVrzZip-=Kt9SK$%=|x59}T89)DL@IuKc2o8LlDvcI!r18PgSZj6YkYFA76$_QK7 zmvKUDz<$?tS;`d22(Zzo^*7&UeMw2T5nXEZ+4QQzUhHYMUMveiz`n)9wJjObyDc8V zLWijbeDjG4?>6FDozt@jqLGAY_3Tb zuiIo16dGbq`x>}a_m%Of%9y}py}{}3@uT$Qsi)pAzXO5`stN3bnTS zjxw$6IQbB|_MHW$E^I=<1}Yfz)nqV~x3tW*eeKMl#?uS~y~D}y6BDWyxEQR-xb-GWcV!B6I|f#=3?gZU6AXhRwS~yGjj~moH;)DIf-r?=@!Je!s-$ zMmc8=stFm*UxfMPX+5aaz&JfUO%{Hg=l|$~+|$_9evE9%k^@cFUs#fc!GmT4@^|Yg z_KA#fvUwxE)nqF$3^CLIV0~=57a5Z!JfX@~0+Kyp3c3bBzTP~MfPFeVcYbizh=#aB zj|HQTM>Fz!PnjUwUNaY>LLUOebRb%n`>q@RNpVG~T zLW!=uF~I(TTIJ&6qNs|08qI`)%ekZ_BH#4>Q ze_t$$yO*W_QHn&S9vioushcq@c?oK1jlODAT*!u!{UDo>ugI0bv88n+1avBs3h_fa=eZ^vQuNW@nP|@iL!UtOJ24L5NkP=+f$AVEu}r z!EY2(x%5G-kR*;fhkq{xRl^j}-_aNv71OTEphZ)N(>_cP&&y7eiQ54 z7JPU>t$n@7B!?YIwP8zit4i}M^*zd zXg6A&=zbvlp$&=$zw;|`ab8elUQBn^-EG|daT#QD!7fPa{{T{Nu4jL02iWxH?@ckA z@J9YbJo;263V*XOfa?wV0uum9l5E-b|6PVe311zi7V(!zH>Goagl2aZn@|~JQjt+2 zH|*P?_~K=~n%-3j2_#_bR@#&2x6r}HbhcS#%Wxc9d-Le19?#8efWnEjDTKit}? zQ~CP@M|AosaS}oE%rr)3%`Gb{SiqvFos_!MfDdCH~I3wtkBk z3h)atxpkX?1Pcv2Jf#f910x_dpMm?oaXF>)NZ3sXgX!EY+#LJq*4e^Gw6P(>%~D1D4T9@ zxT#qMQJHLWj)8l+yXjreMyC=~5XgP`O@_?6rgBC~jalCTSpg|lZJc)^pPk?w9I8Bl zkbdjl3EubQ%BGMQy)M=RNsTPng6}6&HXzq{s@twIUN}GhC#fi4mu`4)2q^hqG$lc% z3G9JNovOmFvcn@r`2cE5dKT+~u8T@}cg`)}>Z5f4wMmt@MT7t#1MH3pmmM_#jU<+d z6drzz+Xt~)0K_c3vvI+`HjPk&5LDfz?Ri4KuhUQ};j;C}{;tB|o|PyTR4j{;lMs6`&*cRv0>E^cvhG>rwd za6Dz_R>j^F7YaJlsOMLFaC?E8nGHm&=3*74*D+jK#|iQ@cn_XM1hx&pfqMyb3{$B^ zs*Rfkxf!Vl;6K!{=d7+pzjmWB9?CMuq68kuC*+?;-1jQ%>zHG-Bc(9`6<|7vsj32{ z5zYh)fgv6ZggSYrOPs-xI-2J&LAZ&V6zeOwL)Piz7Q-?Av)GOsTVJsCN`v3=BE?MA za1eq5S(}^PHI@z&A+YA<&+W2zu>1YX%t?Pvuii^-K|d;3K zw^ucI*>CQuabMJEE|OZF&TtiyZu(w;URS8~58<_x3t#FhFngvO(NxxFqzZ|4>DIOg zARy<#rq~i;{;lLF3DZO~H2c|)$w;sZL@+doV2<9l=);SZ^nY0-fB6fg|FHAFFySEs z$J0l*pU&Cz-tDvuUhhyjfr0o>!9!XR7&DD}IaE>f!dE zAlJQ)Gg6L~8NUkLgbWL}E%%WsGV!~JTj}If@9R(df1#v(x)m|3MSamBDB5ix^c>st zvRa!l5qjIcvU`aow*NkJ!vuRMoev#yAD;tiGMTmJV`xoAMT|v()-~#f*82k2D_=gf z$K+=E80r)kFLPhe+DD$4RHc%Y%NJR=m%y3(`XEo)s*zcLMgG5(H`f1cd9&^k{6hJs zywS7z|2~O-cl1Emq*fI*U3pSWGYksCWY_LoH^bLXi=?+ww*V-V{)Ts%ny33--^q@! zfiiL`O9%oA!6KPEHB6*_d)$D}Z)y%kj2=0n@ape>e=xaR^aQw~Nl+QRw!1pa<=?>z}J$4_f)d>)vgAcV02+U89jVy5LoLgo zUX2@r!N*AHJf*f$PxUhIN85D&tB{RtoOsT0&3$W2OdBr) zN>qmEZI^EWnOZSEI9DJ~Gn`Gdf$@sQu-%M!k3xYq`xBVOs^@y5SK|UI58ok{Xm2b* zO0^SP9z&rK;E62m_+f+ZIxXrz18(K{vNML3Tx~YvDFGSS(a8C&EGM+ZJrz*5ed;( zetNsF`8_Ekm$Gzt?+_nJ0MZKqt6Pe`LW38BtGcA zG;#v=g4kr^()%_BI3RNXy9l)@^?IT4&gm8)`Ndm3NOEV}ecYkDf_!oT2gI3I7WYCy zYylV560@I0?EV}g6IU@_|IlmRYuVGFr4yKNZ2D2|Z0E(e=8J;y_0J4hHMh6zK9#NN zUI1A5Bv~#SL@k?(m0i`g=~BQY^rM}|j$GnI*N_Eu8)>qtytltQ!n}7JyM$nu3g5qf z2U%vx1A1HDtBiauNC9k*{m}k6XPqge?(Y&x5c@}n-O71w8shs!QNs6KM)jM_m=a`T7wHQZW|~!hC1?j}Sm5csNdGCd6j1cPAQ+P&J{LT~%2 z%MK4CBO~S3dcvx`wY!^N#Tkh%i<`gSSvZaQDB!m>Ah_gNdOMW}k}Tx!vWZu#nZC_Z zstjl#KtDHlL4XcsSC~`M!$dyD`z%$s4{l0^2k{~7J9f$-GH8~-kat__CZKn|^gd=12Pv7m{6OY(Oeg zOm#AFV92%(T-X`T^_SyEh4w9b3@1&N^_az$${;cgf)WN*vj+8@f$RBZVB|_9>2KCQ zn<)slP=5Yi5eY)%PZmu!3nN6?zPKRvOEiyVpwMg2Thi|U(ZxglZISEIv)yWNJZai^ zBJ#)ICVN%Ig>)|Aq5JU*K-&3}hmrh-)B1RrPd}3Z0z}{cjIRierlswlU*d8Tv~^t| zGTq+c0ncSn9z7k+$k~~_Dth=ESk|*&)-f=&XZu=Cj^xIN_4>88{5?swg% z$=Xc%^-+tGK*=;IxK2N9uNp>}W!xw;{+Gze2xzQPjF$p!DjH+sloK>$TYJ+(KNxvVcA|!e% zX%H389+#2y+Hg|)8sFjUJBB$qtuwO>JFb1U9-QqN@=D!=*$RPF(#XSIk?Y|NYzpu` zc<6d(2%WM6WvW?M1Z;jo&SbTQLs^MpAa7y_667H1RB|=GX_bLa^<%!DTE%=g3;wuW zYg-rz0%{z5IpQDXMvm&x(O~V8;`|(K8*21ZrO zKoni}m{6Yh0>aRSHOX}>ye0KQ+BbJKq^NjHD>io43S<|=2VW+-?AU+D9Dmirin1(9b z>J7oh{Zb1k-2Z>8FT(d*l@K5x&x^G2cA@S!cIZP~+^yH=iZvRH#h){T@PUW3COfT| zHYY|#{umj<-@jK*x2U(5{4`ESGHZJEN{ahtuYl;P;JLvUj4_AWygA)R&o>w7)ju}vZ8R1 zuJWGaGLYM+SJw=thYZ5wLxA$$py1l+TOeS5v$^?9Fx>mY!Z^rHnDs>Ya3as6IlGxA zvP}`;-dfzjLpP<~NYh%%Bo8FOLGH<|STZY^cm8nUO%#0}xgLdFG6Kp!q?v`_>g240mlo}j)O2b$i2^WE(W?@wpI4^WGjyv+60xA z)}~H@3d0&dpl>t4XlOd-6k3d2rHiIcmIce|{4jDhqSBupm#Tz<(YYsN9|okxD-%?o z*8L#Rd!SIGU*oY)vw%RIQ0gsOBb;eA+-TLSWBo1f@M*7^M<4rttX|M7xOWl;$9PLL zLUF)it(=22!HETBlsD7{tpm|5OD7;zp(j5q2y*k8HdwGkUPZV}u=L_bOf9u9HI|$? z6Zvn7Bl7|-f!ScN42OuD%RfIqFU1N@7&#}Zxb-C;&K7nyN|LirkbWyMF~Wu$<=>xvwrVWgwUEj{QfT( z5^vO+Q@f4YLGP;C(PN=h$o!p;4kG>>bFOpVSfx|W>kJ?N4&r;HPHJz-%YelI38LqU zYw2_VIlTYE{Rh-w{sXA_FD(-Izbq>dA74^li-~%OJ8G7%Sx6rd2v*zF(BCh-`gwTB z{NGuf@DB%$xJvlE*)tkdhGO~MCBwRpyViKkkWUSz*4U+YI{H2S?YMoEkfn~gX`!XUw>3LPg$G2Qm!}}5DDtRl&iouVo!_+^kC?Xb>yHAj(0%gPY zG{|P6Cj<60Tq3YkU9=W@Jr&>mwe9^^u>T4y=ayi@7SEdJ4hMx=p5I1rlt|Uvh)vN7 z%&WNWRp{aWh*q7(+ELBg`>K^vw7|i0v*S5}B!@6sc(&9?pVUdsFi8yv_Ns0VZXmeBhi-z7=W2ID4hMnPf&G+7InCSN9j5E*3RBU)Hzz%LU=-=>JXRWp>e z&_FQ-vcN&JAb{9Dr+ki;qj8#=g~s6-Lu`Ru&ryaT?jp^o!^UUq6pX#A!KyZ0Lf@^ z5Ypn=+1}p{?Tqy(yBWU7k}ta4sR?yu49l9oirW`Msx{VZAwMCfuOLgBXbnGNsO<^# zKyOhSaCxRQngs<}6BJbm5C8@g#{J9-r-djKI;4Q&zp40$B3P(xa#OV{fg7Fro)7d94PeIs6t{t~%P*&R>Y`RXQw+mQOm8MbwmawyvCa zRxDYDfdy#O{S`~5QWv)lL;L~L@E@$60^@q2+=bfvt;;xEo7+qnAbPV3=)hpgIXb$j zJCC@bga->U0M!Re4?w(@@~U9|*h#nCO@wm*Bono;>P*g5HfpzwxRvSR5sNsL3legb zo`VL{?XeELMXkShsF<@X|pm`|2TWLUZYhs<#Kwkd?^CNwW{%^>t-T;Ayg1h*yUHN;^12V z&a^mHtg>3x)+c1phc*P{G4x2qS6d{-!?HIwcYC!9zyxr(iCVo6-aw%|Yu{t7a(9h$ z+CQ-g#7Z+3jXTa^Lulh4^!5Gfx2LHZ$fs3K{!Q>P?X#RIMTW;UMj(t_{6M=IM>Mms ziUdHVSYyXkwpq7tq3>CM-)mSnv^ z6;ax5)DhVDMmSDh>`|)rg+ssaQ3FokIh`ID(pp2yw-k%tDN|<^$iQ%sex3i}v)szX zPS1+ZM2geTx{;H5*q+-D5Tyl?>P4T$r>A{bR%QpvM2L7?4>!H@*y`>)YE4(T4{{ct zy7V`G-@RWV-L5Qx;lqtsDEw0r9;^{y(sn)HS*V|DG|-MF69@%sVl#*Id|M0z24lFW zLCpLeNwR|T5%W)O*OQrTg~A=5FG9nLwLUTjSsg!c$4#$1N4yH#Ty>OS@T=&xD2_?m zM>SeyVzE=+@-Dz3TU5wd^wGo6Bl<4ry09a9ANK+T^}}mc@8L_wb!K*-ED*0##6try zF>TlMeSPPgYZES4Znwc>ChY2+dbV4(Mf4+25v48SbMNGuuf99`*^}89KRx!@e+R4{#@Bv zkIs0~`j+l#U~wAjL%+GsN6tjot6gioARMTnHY>-7{!3(# zbx7$j!t#40lBP83S4QDue_qDTW)W*1_e^# zG(FTbUVgV`HM%yGFzH%?nXOjRz{Flon$cK)rYm3RW6E}#CtGsf;hJteK3FzCS2<$+ zP(xcg@!GY#Cv>k!FN(lDyTE+odG>tj7wE-9d6|zZ#|0Alv(7$6@H=`O!_A5PHy+O} zejrXIVw$!r?7W$3RT3ld|IaSVxqHZ*KnI%mU!D4NC4Jkh)3pT4rU%yA%qMM#gBl3o z4&c}R&3^om)ba2koB$dvip*5F?Ib$#)d=J6kl6=g(mYR2$L~*iFdQSR8dMs!>()qb z-jTBPz6>HgF44M!K)fq7?hePN?ICS)MexGZviK0fPX$Ix};qZO9=sgWF+Lp%R~(V{|9knoDBc~ literal 19997 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/min_distance_preview.png b/doc/salome/gui/SMESH/images/min_distance_preview.png new file mode 100644 index 0000000000000000000000000000000000000000..c5373d99fec12206f646ea7650c049992ddba6c6 GIT binary patch literal 116380 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 z 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 $hQr;pNQ*qqNeE3l3i4XX! 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 uX^WRc@4Yb4#jK@+*Q&R>yb97ox0ki^ zCf6s5tp-_>FZ9&kd68`ZJ|a=7Eu^RCvR%Q=H(zRR<%O>|Lc0V*ugBK5IseVEEBL}| zx^13wk4biTXM1oKZr_zskg@6-`q9}L+7xnic)0R?E2UR$5^AY*UWyBe1Rvz4;N4AL z=6@4X|4#&&slQ6^&2V@H*O6|ls?(c^u6S_LGMuX75_f|Y*cQCF-%XNgp6!L9e$xL~ zi3P_vNl;VJAVC?nBai>ur`1+U4|9|G{rLaAEVrF>)+1r+Y`-R%!x9AhKh%AE^t2}f zWJqVzyCsIHouU7SHl`9~RkU$!@)3ud3x82~%>CAAUZ8`pp&)ZuhVEgWe(XrZgRtZ+ z^wK@vjtJc$6u6TjGXZWWO!ZZXOHqUg1$%-v9v_5O_dNNiTgKHEhl`DT5dFCvhav>k z6ucHhM!qp~kBE^owN8pukM7}It?c*@=R>N5Im*??ya65U;`Ki+hu)n4I!l5re?Xtx zxI#9P>RW_**kbZmbAJ+|u+kZ2zHVpUf;Ai!dleUA9`B&@J+e8)HDwj^r6Cf3IGk|f zKAGQ~p+Cv~9u7v21O=D!c^|w6(aRuOi^@DQ=UgwA~E;( z5bUdCF&5k2sFtLgRhWc<4qNILHkAPa|A&?IrX;?O!^tz}_DXJ-)yfwPp`SP?jUtdL zEwYwqR7_IdDy%Wnm`x%Y+w1pdK`iLd@gU@r=$$C?--&j_=d;@k)k;ne&w2ts-VXoC zZwb1&a%7>85WZAEcZY2TOgrS{)S(DGd}^Ic@oUurGd_wi0TQ&-dQ4 zq`jZv8C*g%%I)y!BSA)wopBCiWZW-6)91L-4Jn+7smch#Hd{!^FavbU4@4x zqTW3`A)T`>Uc4&E0^NHTpp*u|3#1jM`rn`>(!`)SDy}?5h2^gpfmTv;!!xBk?iQc( zM(zN-G@8ruUUsEQOs8!;oUWSVyK)AoHC#mj1!i!YA~{9!-U=EmbV3_Asf|qY-v71~ z+f)YXw3703g`?U&tKC>#0{#B&WDw`l_?ZIk6 zFlROep0h5LW)+r}K`s>ISBw7Rl{rdmmBzlvj$;Qb^=9)2X#BZhpI@;S{=k%1WS9-)VV zSo~&+0hRMd;(wWYms$rQQ7&s#EsUN0Vg`yqHnO`&VZK@PLfNT)BM&CE(5`dbB zDI^>Unsw|>lM*|lHq}KOewoUh1dV^(B5!!21Z)iRr_FDoYbMko|*2!qzuLY((f z6Z!G}rn^lE>M1CCtdA0X@#b0OU~+;}5z7h&PP>rgz?};6|Fp|nlkWlP4Ccw- zrq&Zqp?y|Gdr1X?VoxM90y9!+AuT**^`6%|n+HR9*2l@x?0I;hkTA8?(8vF7ts5uSq%=sA=OgExp%Mm;bjdJE&e=c(X|dv@}?Sah}=s%Iy0ml*}-8t&7d zQ>Vxa$BV@85WR2zS^s^?kc(GDo$2^yFRHElCsxF%xO4qpy92st6x?_8nhz>1y13_J z==)rhE=Rj}zv|`cqrj_RqmW&^c4K>WcynEzE!G{Q6o4OfX=q?ebna(-Zuq+RZkBp2 z04sU_GQF+@&b~)Tuvl^9qa9;iivm|3w1WAG2kMiz%@u=UmOgruh2et(mo`?y8g_vf zB*!f^ES)h$?docAgM#ld)d*gYb4`#_Qf~!6I&P_prEJ0r zl8QmeA}u}CPwc)bPtuD43@f>=7>4qGD<#^{myv7Q8`lyxz9GrH3jMqQ*I)m|5sDuX O1GLn1RjZY)BmM_Lk9#Em literal 15776 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 KRE>nmkN*Su?S)AI diff --git a/doc/salome/gui/SMESH/images/moving_nodes2.png b/doc/salome/gui/SMESH/images/moving_nodes2.png index b65e57ae97af9cf397aa8493ce51039f5b581ab8..a89e8b36b3bb65119e2dd23cf4db07b52347ad38 100755 GIT binary patch literal 6900 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 literal 20232 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 WuI&2BGmVk>R_fyA3yI=49{w*Qg>|(6 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/netgen2d3d_simple.png b/doc/salome/gui/SMESH/images/netgen2d3d_simple.png new file mode 100644 index 0000000000000000000000000000000000000000..50ca0a0603c82cc1f3f1a026bc8b173a8440c927 GIT binary patch literal 32547 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 V7x=OO9-l{3kX4o`l{WhD{{W_oml*&6 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/netgen3d_simple.png b/doc/salome/gui/SMESH/images/netgen3d_simple.png deleted file mode 100644 index 959ec02c8996033167b16a39b068555607e3b503..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26853 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®sKR1GXI-DHQJ5y>1-E$*0K! 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

  • \ref arithmetic_1d_anchor "Arithmetic 1D"
  • -
  • \ref average_length_anchor "Average Length"
  • +
  • \ref average_length_anchor "Local Length"
  • \ref max_length_anchor "Max Size"
  • \ref deflection_1d_anchor "Deflection 1D"
  • \ref number_of_segments_anchor "Number of segments"
  • @@ -57,9 +57,9 @@ locations and 1D mesh elements are constructed on segments.
    \anchor average_length_anchor -

    Average Length hypothesis

    +

    Local Length hypothesis

    -Average Length hypothesis can be applied for meshing of edges +Local Length hypothesis can be applied for meshing of edges composing your geometrical object. Definition of this hypothesis consists of setting the \b length of segments, which will split these edges, and the \b precision of rounding. The points on the edges @@ -79,10 +79,10 @@ integer. Default value is 1e-07. \image html a-averagelength.png -\image html b-erage_length.png "Average length hypothesis - all 1D mesh elements are roughly equal" +\image html b-erage_length.png "Local Length hypothesis - all 1D mesh elements are roughly equal" See Also a sample TUI Script of a -\ref tui_average_length "Defining Average Length" hypothesis +\ref tui_average_length "Defining Local Length" hypothesis operation.
    \anchor max_length_anchor @@ -157,7 +157,7 @@ operation. Start and End Length hypothesis allows to divide a geometrical edge into segments so that the first and the last segments have a specified -length. The length medium segments changes with automatically chosen +length. The length of medium segments changes with automatically chosen geometric progression. Then mesh nodes are constructed at segment ends location and 1D mesh elements are constructed on them. diff --git a/doc/salome/gui/SMESH/input/2d_meshing_hypo.doc b/doc/salome/gui/SMESH/input/2d_meshing_hypo.doc index 892cc9f74..d72e4d504 100644 --- a/doc/salome/gui/SMESH/input/2d_meshing_hypo.doc +++ b/doc/salome/gui/SMESH/input/2d_meshing_hypo.doc @@ -43,27 +43,58 @@ length calculated as an average edge length for a given wire. \anchor hypo_quad_params_anchor

    Quadrangle parameters

    -Quadrangle parameters is a hypothesis for -Quadrangle (Mapping), which allows using this algorithm for meshing of -triangular faces.In this case it is necessary to select the Base vertex -used as a degenerated edge. +\image html hypo_quad_params_dialog.png "Quadrangle parameters creation/edition dialog" + +Quadrangle parameters is a hypothesis for Quadrangle (Mapping). + +Base vertex parameter allows using Quadrangle (Mapping) +algorithm for meshing of triangular faces. In this case it is +necessary to select the vertex, which will be used as the fourth edge +(degenerated). \image html hypo_quad_params_1.png "A face built from 3 edges" \image html hypo_quad_params_res.png "The resulting mesh" -This hypothesis can be also used to mesh a segment of a circular face. -Please, consider that there is a limitation on the selectiion of the degenerated +This parameter can be also used to mesh a segment of a circular face. +Please, consider that there is a limitation on the selection of the vertex for the faces built with the angle > 180 degrees (see the picture). \image html hypo_quad_params_2.png "3/4 of a circular face" -In this case, selection of a wrong vertex for the Quadrangle parameters -hypothesis will generate a wrong mesh. The picture below +In this case, selection of a wrong vertex for the Base vertex +parameter will generate a wrong mesh. The picture below shows the good (left) and the bad (right) results of meshing. \image html hypo_quad_params_res_2.png "The resulting meshes" +Type parameter is used on faces with a different number of +segments on opposite sides to define the algorithm of transition +between them. The following types are available: + +
      +
    • Standard is the default case, when both triangles and quadrangles + are possible in the transition area along the finer meshed sides.
    • +
    • Triangle preference forces building only triangles in the + transition area along the finer meshed sides. + This type corresponds to Triangle Preference additional + hypothesis, which is obsolete now.
    • +
    • Quadrangle preference forces building only quadrangles in the + transition area along the finer meshed sides. This hypothesis has a + restriction: the total quantity of segments on all + four sides of the face must be even (divisible by 2).
    • + This type corresponds to Quadrangle Preference + additional hypothesis, which is obsolete now. +
    • Quadrangle preference (reversed) works in the same way and +with the same restriction as Quadrangle preference, but + the transition area is located along the coarser meshed sides.
    • +
    • Reduced type forces building only quadrangles and the transition + between the sides is made gradually, layer by layer. This type has + a limitation on the number of segments: one pair of opposite sides must have + the same number of segments, the other pair must have an even difference + between the numbers of segments on the sides.
    • +
    + See Also a sample TUI Script of a \ref tui_quadrangle_parameters "Quadrangle Parameters" hypothesis. diff --git a/doc/salome/gui/SMESH/input/about_filters.doc b/doc/salome/gui/SMESH/input/about_filters.doc new file mode 100644 index 000000000..22d88635f --- /dev/null +++ b/doc/salome/gui/SMESH/input/about_filters.doc @@ -0,0 +1,31 @@ +/*! + +\page filters_page About filters + +\b Filters allow picking only the mesh elements satisfying to a +specific condition or a set of conditions. Filters can be used to create +or edit mesh groups, remove elements from the mesh object, control +mesh quality by different parameters, etc. + +Several filters can be combined together by using logical operators \a +AND and \a OR. In addition, applied filter criterion can be reverted +using logical operator \a NOT. + +Mesh filters use the functionality of \ref quality_page "mesh quality controls" +to filter mesh nodes / elements by specific characteristic (Area, Length, etc). + +The functinality of mesh filters is available in both GUI and TUI +modes: + +- In GUI, filters are available in some dialog boxes via an additional +"Set Filters" button, clicking on which opens the dialog box +allowing to specify the list of filter criterions to be applied to the +current selection. See \subpage selection_filter_library_page page to learn more +about selection filters and their usage in GUI. + +- In Python scripts, filters can be used to choose only some mesh + entities (nodes and/or elements) for the operations, which require the + list of entities as input parameter (create/modify group, remove + nodes/elements, etc). The page \ref tui_filters_page provides + examples of the filters usage in Python scripts. +*/ diff --git a/doc/salome/gui/SMESH/input/about_hypo.doc b/doc/salome/gui/SMESH/input/about_hypo.doc index 0e8ac1007..5f989ec3d 100644 --- a/doc/salome/gui/SMESH/input/about_hypo.doc +++ b/doc/salome/gui/SMESH/input/about_hypo.doc @@ -17,7 +17,7 @@ them, you operate numerical values): edges):
    • \ref arithmetic_1d_anchor "Arithmetic 1D"
    • -
    • \ref average_length_anchor "Average Length"
    • +
    • \ref average_length_anchor "Local Length"
    • \ref max_length_anchor "Max Size"
    • \ref deflection_1d_anchor "Deflection 1D"
    • \ref number_of_segments_anchor "Number of segments"
    • @@ -29,8 +29,6 @@ them, you operate numerical values):
    • \ref max_element_area_anchor "Max Element Area"
    • \ref length_from_edges_anchor "Length from Edges"
    • \ref hypo_quad_params_anchor "Quadrangle Parameters"
    • -
    • \ref quadrangle_preference_anchor "Quadrangle Preference"
    • -
    • \ref triangle_preference_anchor "Triangle Preference"
  • 3D Hypothesis (for meshing of volumes):
    • diff --git a/doc/salome/gui/SMESH/input/about_quality_controls.doc b/doc/salome/gui/SMESH/input/about_quality_controls.doc index 0d7ab61b0..8f78c38c5 100644 --- a/doc/salome/gui/SMESH/input/about_quality_controls.doc +++ b/doc/salome/gui/SMESH/input/about_quality_controls.doc @@ -13,24 +13,25 @@ the meshing elements and these calculated values is shown with the help of a scalar bar, which is displayed near the presentation of your mesh. -There are 0D, 1D, 2D and 3D quality controls. +There are four types of quality controls, corresponding to node, edge, +face and volume entity type. -0D mesh quality controls: +Node quality controls:
        -
      • \ref free_nodes_page "Free nodes"
      • +
      • \subpage free_nodes_page "Free nodes"
      -1D mesh quality controls: +Edge quality controls:
        +
      • \subpage free_edges_page "Free edges"
      • \subpage free_borders_page "Free borders"
      • -
      • \subpage borders_at_multi_connection_page "Borders at multi-connection"
      • \subpage length_page "Length"
      • +
      • \subpage borders_at_multi_connection_page "Borders at multi-connection"
      -2D mesh quality controls: +Face quality controls:
        -
      • \subpage free_nodes_page "Free nodes"
      • -
      • \subpage free_edges_page "Free edges"
      • +
      • \subpage free_faces_page "Free faces"
      • \subpage length_2d_page "Length 2D"
      • \subpage borders_at_multi_connection_2d_page "Borders at multi-connection 2D"
      • \subpage area_page "Area"
      • @@ -39,13 +40,14 @@ There are 0D, 1D, 2D and 3D quality controls.
      • \subpage minimum_angle_page "Minimum angle"
      • \subpage warping_page "Warping"
      • \subpage skew_page "Skew"
      • +
      • \subpage max_element_length_2d_page "Max element length 2D"
      -3D mesh quality controls: +Volume quality controls:
      • \subpage aspect_ratio_3d_page "Aspect ratio 3D"
      • \subpage volume_page "Volume"
      • -
      • \subpage free_faces_page "Free faces"
      • +
      • \subpage max_element_length_3d_page "Max element length 3D"
      */ diff --git a/doc/salome/gui/SMESH/input/adding_nodes_and_elements.doc b/doc/salome/gui/SMESH/input/adding_nodes_and_elements.doc index 5c99e8e79..c0168994b 100644 --- a/doc/salome/gui/SMESH/input/adding_nodes_and_elements.doc +++ b/doc/salome/gui/SMESH/input/adding_nodes_and_elements.doc @@ -27,23 +27,23 @@ following associated submenu will appear: From this submenu select the type of element which you would like to add to your mesh. -\note All dialogs for adding new node or element to the mesh (except for -the dialog for 0D elements) provide a possibility to add it -automatically to the specified group or to create it anew using -Add to group box, that allows to choose an existing group for -the created node or element or to give the name to a new group. By -default, the Add to group check box is switched off. If user +\note All dialogs for new node or element adding to the mesh (except for +the dialog for 0D elements) provide the possibility to automatically add +a node or element to the specified group or to create the anew using +Add to group box, that allows choosing an existing group for +the created node or element or giving the name to a new group. By +default, the Add to group check box is switched off. If the user swiches this check box on, the combo box listing all currently existing groups of the corresponding type becomes available. By -default, no any group is selected. In such a case, when user presses +default, no group is selected. In this case, when the user presses Apply or Apply & Close button, the warning message box -informing the user about the necessity to input new group name is -shown. The combo box lists both \ref standalone_group "standalone groups" -and \ref group_on_geom "groups on geometry". If the user has -chosen the group on geometry, he is warned and proposed to -\ref convert_to_standalone "convert this group to the standalone". -If user refuses converting operation, an operation is cancelled and -new node/element is not created! +informs the user about the necessity to input new group name. The +combo box lists both \ref standalone_group "standalone groups" +and \ref group_on_geom "groups on geometry". If the user chooses a +group on geometry, he is warned and proposed to +\ref convert_to_standalone "convert this group to standalone". +If the user rejects conversion operation, it is cancelled and +a new node/element is not created! diff --git a/doc/salome/gui/SMESH/input/adding_quadratic_elements.doc b/doc/salome/gui/SMESH/input/adding_quadratic_elements.doc index 83736c85d..921948630 100644 --- a/doc/salome/gui/SMESH/input/adding_quadratic_elements.doc +++ b/doc/salome/gui/SMESH/input/adding_quadratic_elements.doc @@ -18,23 +18,23 @@ one of the following: \image html image152.png -\note All dialogs for adding quadratic element to the mesh -provide a possibility to add new element -automatically to the specified group or to create it anew using -Add to group box, that allows to choose an existing group for -the created node or element or to give the name to a new group. By -default, the Add to group check box is switched off. If user +\note All dialogs for quadratic element adding to the mesh +provide the possibility to automatically add an element +to the specified group or to create the group anew using +Add to group box, that allows choosing an existing group for +the created node or element or giving the name to a new group. By +default, the Add to group check box is switched off. If the user swiches this check box on, the combo box listing all currently existing groups of the corresponding type becomes available. By -default, no any group is selected. In such a case, when user presses +default, no group is selected. In this case, when the user presses Apply or Apply & Close button, the warning message box -informing the user about the necessity to input new group name is -shown. The combo box lists both \ref standalone_group "standalone groups" -and \ref group_on_geom "groups on geometry". If the user has -chosen the group on geometry, he is warned and proposed to -\ref convert_to_standalone "convert this group to the standalone". -If user refuses converting operation, an operation is cancelled and -new node/element is not created! +informs the user about the necessity to input a new group name. The +combo box lists both \ref standalone_group "standalone groups" +and \ref group_on_geom "groups on geometry". If the user chooses a +group on geometry, he is warned and proposed to +\ref convert_to_standalone "convert this group to standalone". +If the user rejects conversion operation, it is cancelled and +a new quadratic element is not created. To create any Quadratic Element specify the nodes which will form your diff --git a/doc/salome/gui/SMESH/input/additional_hypo.doc b/doc/salome/gui/SMESH/input/additional_hypo.doc index 1205e19b0..81eab0be8 100644 --- a/doc/salome/gui/SMESH/input/additional_hypo.doc +++ b/doc/salome/gui/SMESH/input/additional_hypo.doc @@ -41,17 +41,20 @@ It allows Netgen 2D to build quadrangular meshes at any conditions. It allows Quadrangle (Mapping) to build quadrangular meshes even if the number of nodes at the opposite edges of a meshed face is not equal, -otherwise this mesh will contain some triangular elements. +otherwise this mesh will contain some triangular elements. This use +case is obsolete now. Use Quadrangle Parameters hypothesis with +type Quadrangle Preference set instead.
      This hypothesis has one restriction on its work: the total quantity of segments on all four sides of the face must be even (divisible by 2). -

      Triangle Preference

      +

      Triangle Preference (obsolete)

      This additional hypothesis can be used only together with Quadrangle (Mapping) algorithm. It allows to build triangular mesh faces in the refinement area if the number of nodes at the opposite edges of a meshed face is not equal, otherwise refinement area will contain some quadrangular elements. - +This hypothesis is obsolete now. Use Quadrangle Parameters +hypothesis with type Triangle Preference set instead. */ diff --git a/doc/salome/gui/SMESH/input/area.doc b/doc/salome/gui/SMESH/input/area.doc index bef0c0f8a..f650a3fd6 100644 --- a/doc/salome/gui/SMESH/input/area.doc +++ b/doc/salome/gui/SMESH/input/area.doc @@ -11,7 +11,8 @@ quadrangles).
      1. Display your mesh in the viewer.
      2. -
      3. Choose Controls > Area or click "Area" button. +
      4. Choose Controls > Face Controls > Area or click +"Area" button. \image html image35.png
        "Area" button
        diff --git a/doc/salome/gui/SMESH/input/aspect_ratio.doc b/doc/salome/gui/SMESH/input/aspect_ratio.doc index 070d377cc..c6c3dbdee 100644 --- a/doc/salome/gui/SMESH/input/aspect_ratio.doc +++ b/doc/salome/gui/SMESH/input/aspect_ratio.doc @@ -13,10 +13,10 @@ nodes is calculated by the formula: \image html formula4.png -- The Aspect Ratio of a \b quadrangle 2D element consisting of - 4 nodes is the worst (i.e. the greatest) value from all triangles - which can be built taking three nodes of the quadrangle. There are - four triangles to consider: +- The Aspect Ratio of a \b quadrangle 2D element consisting of 4 +nodes is calculated by the formula: + +\image html formula5.png \image html image138.gif @@ -24,8 +24,8 @@ nodes is calculated by the formula:
        1. Display your mesh in the viewer.
        2. -
        3. Choose Controls > Aspect Ratio or click "Aspect -Ratio" button in the toolbar. +
        4. Choose Controls > Face Controls > Aspect Ratio or click +"Aspect Ratio" button in the toolbar. \image html image37.png
          "Aspect Ratio" button
          diff --git a/doc/salome/gui/SMESH/input/aspect_ratio_3d.doc b/doc/salome/gui/SMESH/input/aspect_ratio_3d.doc index 751e41102..6e8b70808 100644 --- a/doc/salome/gui/SMESH/input/aspect_ratio_3d.doc +++ b/doc/salome/gui/SMESH/input/aspect_ratio_3d.doc @@ -21,8 +21,8 @@ by the formula:
          1. Display your mesh in the viewer.
          2. -
          3. Choose Controls > Aspect Ratio 3D or click "Aspect Ratio 3D" -button of the toolbar. +
          4. Choose Controls > Volume Controls > Aspect Ratio 3D or click +"Aspect Ratio 3D" button of the toolbar. \image html image144.png
            "Aspect Ratio 3D" button
            diff --git a/doc/salome/gui/SMESH/input/basic_meshing_algos.doc b/doc/salome/gui/SMESH/input/basic_meshing_algos.doc index e957a9713..274ab7438 100644 --- a/doc/salome/gui/SMESH/input/basic_meshing_algos.doc +++ b/doc/salome/gui/SMESH/input/basic_meshing_algos.doc @@ -62,6 +62,7 @@ license to be used within the Mesh module. There is also a number of more specific algorithms:
            • \subpage projection_algos_page "for meshing by projection of another mesh"
            • +
            • \subpage import_algos_page "for meshing by importing elements from another mesh"
            • \subpage radial_prism_algo_page "for meshing geometrical objects with cavities"
            • \subpage segments_around_vertex_algo_page "for defining the local size of elements around a certain node"
            • \subpage prism_3d_algo_page "for meshing prismatic shapes"
            • diff --git a/doc/salome/gui/SMESH/input/clipping.doc b/doc/salome/gui/SMESH/input/clipping.doc index f3b19f374..df3e39495 100644 --- a/doc/salome/gui/SMESH/input/clipping.doc +++ b/doc/salome/gui/SMESH/input/clipping.doc @@ -9,11 +9,14 @@ To start, click on the \em New button. \image html a-clipping2.png -Now you can define the parameters of your cross-section: \b Orientation -(X-Y, X-Z or Y-Z); \b Distance between the opposite extremities of the -object, if it is set to 0.5 the object is split in two halves; and -\b Rotation (in angle degrees) around X (Y to Z) and around Y (X to -Z). If the Show preview button is on, you can see the clipping plane +Now you can define the parameters of your cross-section: list of +meshes, sub-meshes and groups the cross-section will be applied to +(Select all button allows to select and deselect all available +objects at once), \b Orientation (X-Y, X-Z or Y-Z); \b Distance between the +opposite extremities of the boundary box of selected objects, if it is set +to 0.5 the boundary box is split in two halves; and \b Rotation (in angle +degrees) around X (Y to Z) and around Y (X to Z). +If the Show preview button is on, you can see the clipping plane in the 3D Viewer. \image html image79.jpg "The plane and the cut object" diff --git a/doc/salome/gui/SMESH/input/creating_groups.doc b/doc/salome/gui/SMESH/input/creating_groups.doc index 29b17f1ae..85d633a22 100644 --- a/doc/salome/gui/SMESH/input/creating_groups.doc +++ b/doc/salome/gui/SMESH/input/creating_groups.doc @@ -26,7 +26,7 @@ SALOME Platform distinguishes between the two Group types: \anchor standalone_group

              "Standalone Group"

              Standalone Group consists of mesh elements, which you can define in -two possible ways. +the following ways:
              • Choosing them manually with the mouse in the 3D Viewer. You can click on an element in the 3D viewer and it will be highlighted. After @@ -36,6 +36,9 @@ the list.
              • definite filter to selection of the elements of your group. See more about filters on the \ref selection_filter_library_page "Selection filter library" page. +
              • By adding all existing entities of the chosen type to the +group. For this turn on the Select All check box. In this +mode all controls, which allow selecting the entities manually or by filters, are disabled.
              To remove a selected element or elements from the list click the \b Remove button. The Sort List button allows to sort the list of IDs of diff --git a/doc/salome/gui/SMESH/input/double_nodes_page.doc b/doc/salome/gui/SMESH/input/double_nodes_page.doc new file mode 100644 index 000000000..063bcba5e --- /dev/null +++ b/doc/salome/gui/SMESH/input/double_nodes_page.doc @@ -0,0 +1,70 @@ +/*! + +\page double_nodes_page Duplicate Nodes + +\n This operation allows to duplicate nodes of your mesh. +Duplication consists in replacement of an existing mesh element by another one. +Lower level elements of the duplicated ones are cloned +automatically. + +To duplicate nodes: +
                +
              1. From the \b Modification menu choose \b Transformation -> \b Duplicate +\b Nodes item or click "Duplicate Nodes" button in the toolbar. +
                +\image html duplicate_nodes.png "Duplicate Nodes button" +
              2. +
              3. Check in the dialog box one of two radio buttons corresponding to +the type of nodes duplication operation you would like to perform.
              4. +
              5. Fill the other fields available in the dialog box (depends on the chosen + operation mode).
              6. +
              7. Click the \b Apply or Apply and Close button to perform the operation of nodes + duplication.
              8. +
              + +\n "Duplicate Nodes" dialog has two working modes: +
                +
              • \ref mode_without_elem_anchor "Without the duplication of border elements"
              • +
              • \ref mode_with_elem_anchor "With the duplication of border elements"
              • +
              + +
              +\anchor mode_without_elem_anchor +

              Without duplication of border elements

              + +In this mode the dialog looks like: + +\image html duplicate01.png + +Parameters to be defined in this mode: +
                +
              • Group of nodes to duplicate (mandatory): these nodes will be duplicated.
              • +
              • Group of elements to replace nodes with new ones (optional): the duplicated nodes + will be associated with these elements.
              • +
              • Construct group with newly created nodes option (checked by default): + if checked - the group with just created nodes will be built.
              • +
              + +
              +\anchor mode_with_elem_anchor +

              With duplication of border elements

              + +In this mode the dialog looks like: + +\image html duplicate02.png + +Parameters to be defined in this mode: +
                +
              • Group of elements to duplicate (mandatory): these elements will be duplicated.
              • +
              • Group of nodes at not to duplicate (optional): group of nodes at crack bottom + which will not be duplicated.
              • +
              • Group of elements to replace nodes with new ones (mandatory): the duplicated nodes + will be associated with these elements.
              • +
              • Construct group with newly created elements option (checked by default): + if checked - the group with just created elements will be built.
              • +
              + + +
              See Also a sample TUI Script of a \ref tui_duplicate_nodes "Duplicate nodes" operation. + +*/ diff --git a/doc/salome/gui/SMESH/input/grouping_elements.doc b/doc/salome/gui/SMESH/input/grouping_elements.doc index 638d70112..3ec4117c4 100644 --- a/doc/salome/gui/SMESH/input/grouping_elements.doc +++ b/doc/salome/gui/SMESH/input/grouping_elements.doc @@ -33,7 +33,7 @@ The created groups can be later:
            An important tool, providing filters for creation of \b Standalone -groups is \subpage selection_filter_library_page. +groups is \ref selection_filter_library_page. */ diff --git a/doc/salome/gui/SMESH/input/index.doc b/doc/salome/gui/SMESH/input/index.doc index 7e18d2b68..5301ce8de 100644 --- a/doc/salome/gui/SMESH/input/index.doc +++ b/doc/salome/gui/SMESH/input/index.doc @@ -12,10 +12,13 @@ previously created or imported by the Geometry component;
          5. \subpage viewing_meshes_overview_page "viewing created meshes" in the VTK viewer;
          6. \subpage grouping_elements_page "creating groups of mesh elements";
          7. -
          8. applying to meshes \subpage quality_page "Quality Controls" , -allowing to highlight important elements: +
          9. applying to meshes \subpage quality_page "Quality Controls", +allowing to highlight important elements; +
          10. filtering sub-sets of mesh entities (nodes elements) using +\subpage filters_page "Filters" functionality;
          11. \subpage modifying_meshes_page "modifying meshes" with a vast -array of dedicated operations.
          12. +array of dedicated operations; +
          13. different \subpage measurements_page "measurements" of the mesh objects;
          14. easily setting parameters via the variables predefined in \subpage using_notebook_mesh_page "Salome notebook".
    @@ -23,6 +26,10 @@ array of dedicated operations. Almost all mesh module functionalities are accessible via \subpage smeshpy_interface_page "Mesh module Python interface". +Also it can be useful to have a look at the +\subpage smeshpypkg_page "documentation on SMESH python package". + + \image html image7.jpg "Example of MESH module usage for engineering tasks" */ diff --git a/doc/salome/gui/SMESH/input/length_2d.doc b/doc/salome/gui/SMESH/input/length_2d.doc index def8afa95..4ed5b69e6 100644 --- a/doc/salome/gui/SMESH/input/length_2d.doc +++ b/doc/salome/gui/SMESH/input/length_2d.doc @@ -10,8 +10,8 @@ of your mesh.
    1. Display your mesh in the viewer.
    2. -
    3. Choose Controls > Length 2D or click "Length 2D" -button in the toolbar. +
    4. Choose Controls > Face Controls > Length 2D or click +"Length 2D" button in the toolbar. \image html image34.png
      "Length 2D" button
      diff --git a/doc/salome/gui/SMESH/input/make_2dmesh_from_3d.doc b/doc/salome/gui/SMESH/input/make_2dmesh_from_3d.doc index f4b5b2ba5..e52078629 100644 --- a/doc/salome/gui/SMESH/input/make_2dmesh_from_3d.doc +++ b/doc/salome/gui/SMESH/input/make_2dmesh_from_3d.doc @@ -1,22 +1,58 @@ /*! -\page make_2dmesh_from_3d_page Generate the skin elements (2D) of a mesh having 3D elements +\page make_2dmesh_from_3d_page Generate boundary elements -\n This functionality allows to generate 2D mesh elements as a skin -on the existing 3D mesh elements. +\n This functionality allows to generate mesh elements on the borders of +elements of a higher dimension. -To generate 2D mesh: +To generate border elements:
        -
      1. From the Modification menu choose "Create 2D mesh from 3D" -item, or choose from the popup menu. +
      2. From the Modification menu choose "Create boundary elements" +item, or click "Create boundary elements" button in the toolbar -\image html 2d_from_3d_menu.png +\image html 2d_from_3d_ico.png "Create boundary elements icon" -The algorithm detects boundary volume faces without connections to -other volumes and creates 2D mesh elements on face nodes. If the mesh -already contains 2D elements on the detected nodes, new elements are not -created. The the resulting dialog shows mesh information statistics -about the newly created 2D mesh elements. +The following dialog box will appear: +\image html 2d_from_3d_dlg.png "Create boundary elements dialog box". +
      3. +
      4. Check in the dialog box one of three radio buttons corresponding to +the type of operation you would like to perform.
      5. +
      6. Fill the other fields available in the dialog box.
      7. +
      8. Click the \b Apply or Apply and Close button to perform the operation.
      +\n "Create boundary elements" dialog allows creation of boundary elements +of three types. +
        +
      • 2D from 3D creates mesh faces on free facets of volume elements
      • +
      • 1D from 2D creates mesh edges on free edges of mesh faces
      • +
      • 1D from 3D creates mesh edges on all borders of free facets of volume elements
      • +
      +Here a free facet means a facet shared by only one volume, a free edge +means an edge shared by only one mesh face. + +In this dialog: +
        +
      • specify the Mesh, submesh or group, the boundary which of +will be analyzed.
      • +
      • specify the Target mesh, where the boundary elements will + be created. +
          +
        • This mesh adds elements in the selected mesh or the mesh + the selected submesh or group belongs to.
        • +
        • New mesh adds elements to a new mesh. The new mesh appears + in the Object Browser with the name that you can change in the adjacent box.
        • +
      • +
      • activate Copy source mesh checkbox to copy 2D or 3D + elements (depending on the operation type), which belong to the analyzed +Mesh, submesh or group field, to the new mesh.
      • +
      • deactivate Copy missing elements only checkbox to copy + boundary elements already present in the analyzed mesh to the + new mesh.
      • +
      • activate Create group checkbox to create a group to which the + missing boundary elements are added. The new group appears + in the Object Browser with the name that you can change in the adjacent box.
      • +
      +
      See Also a sample TUI Script of a \ref tui_make_2dmesh_from_3d "Create boundary elements" operation. + */ diff --git a/doc/salome/gui/SMESH/input/max_element_length_2d.doc b/doc/salome/gui/SMESH/input/max_element_length_2d.doc new file mode 100644 index 000000000..933ac55ee --- /dev/null +++ b/doc/salome/gui/SMESH/input/max_element_length_2d.doc @@ -0,0 +1,29 @@ +/*! + +\page max_element_length_2d_page Element Diameter 2D + +\n This quality control criterion consists of calculation of length of +the edges and diagonals combining the meshing elements (triangles and quadrangles) +of your mesh. + +To apply the Element Diameter 2D quality criterion to your mesh: +
        +
      1. Display your mesh in the viewer.
      2. + +
      3. Choose Controls > Face Controls > Element Diameter 2D or click +"Element Diameter 2D" button in the toolbar. + +\image html image42.png +
        "Element Diameter 2D" button
        + +Your mesh will be displayed in the viewer with its elements colored according to the +applied mesh quality control criterion: + +\image html max_element_length_2d.png +
      4. +
      + +
      See Also a sample TUI Script of a +\ref tui_max_element_length_2d "Element Diameter 2D quality control" operation. + +*/ \ No newline at end of file diff --git a/doc/salome/gui/SMESH/input/max_element_length_3d.doc b/doc/salome/gui/SMESH/input/max_element_length_3d.doc new file mode 100644 index 000000000..9326ad837 --- /dev/null +++ b/doc/salome/gui/SMESH/input/max_element_length_3d.doc @@ -0,0 +1,30 @@ +/*! + +\page max_element_length_3d_page Element Diameter 3D + +\n This quality control criterion consists of calculation of length of +the edges and diagonals combining the 3D meshing elements +(tetrahedrons, pyramids, pentahendrons, hexahedrons and polyhedrons) +of your mesh. + +To apply the Element Diameter 3D quality criterion to your mesh: +
        +
      1. Display your mesh in the viewer.
      2. + +
      3. Choose Controls > Volume Controls > Element Diameter 3D or click +"Element Diameter 3D" button in the toolbar. + +\image html image43.png +
        "Element Diameter 3D" button
        + +Your mesh will be displayed in the viewer with its elements colored according to the +applied mesh quality control criterion: + +\image html max_element_length_3d.png +
      4. +
      + +
      See Also a sample TUI Script of a +\ref tui_max_element_length_3d "Element Diameter 3D quality control" operation. + +*/ \ No newline at end of file diff --git a/doc/salome/gui/SMESH/input/measurements.doc b/doc/salome/gui/SMESH/input/measurements.doc new file mode 100644 index 000000000..27894a49a --- /dev/null +++ b/doc/salome/gui/SMESH/input/measurements.doc @@ -0,0 +1,71 @@ +/*! + +\page measurements_page Measurements + +Mesh module provides possibility to perform different measurements +of the selected mesh data. + +All the measurement operations are available via \b Measurements +top-level menu. An access to the measurements operations is +implemented via single dialog box, where each operation is represented +as a separate tab page. + +\section min_distance_anchor Minimum Distance + +This operation allows measuring a distance between two objects. +Currently only node-to-node and node-to-origin operations are +available, but this operation will be extended in future to support +other mesh objects - elements, meshes, sub-meshes and groups. + +To start Minimum Distance operation, select Minimum Distance +item from \b Measurements menu. + +\image html min_distance.png + +In the dialog box choose the first target and second target mode by +switching the corresponding radio buttons, then select the objects +between which the distance is to be calculated (or enter directly IDs +in case of nodes/elements) and press \em Compute button. + +The following types of targets are supported: +- \em Node: single mesh node; +- \em Element: single mesh element (not available in this version); +- \em Object: mesh, sub-mesh or group object (not available in this +version); +- \em Origin: origin of the global co-ordinate system. + +The result will +be shown in the bottom area of the dialog box. In addition, the simple +preview will be shown in the 3D viewer. + +\image html min_distance_preview.png + +\section bounding_box_anchor Bounding Box + +This operation allows to calculate the bounding box of the selected +object(s). + +To start Bounding Box operation, select Bounding Box +item from \b Measurements menu. + +\image html bnd_box.png + +In the dialog box choose desired type of the object by switching the +corresponding radio button, select the desired object(s) and press +\em Compute button. + +The following types of input are available: +- \em Objects: select one or more mesh, sub-mesh, group objects; +- \em Nodes: select set of mesh nodes; +- \em Elements: select set of mesh elements. + +The result of calculation will be shown in the bottom area of the +dialog box. In addition, the simple preview will be shown in the 3D +viewer. + +\image html bnd_box_preview.png + +See Also a sample TUI Script of a +\ref tui_measurements_page "Measurement operations". + +*/ diff --git a/doc/salome/gui/SMESH/input/merging_nodes.doc b/doc/salome/gui/SMESH/input/merging_nodes.doc index eb17e0a14..3b1bbeaaf 100644 --- a/doc/salome/gui/SMESH/input/merging_nodes.doc +++ b/doc/salome/gui/SMESH/input/merging_nodes.doc @@ -2,17 +2,18 @@ \page merging_nodes_page Merging nodes -\n This functionality allows user to detect groups of coincident nodes -with desirable tolerance, edit these groups and merge. +This functionality allows user to detect groups of coincident nodes +with specified tolerance; each group of the coincident nodes can be +then converted to the single node. \image html mergenodes_ico.png "Merge nodes button" To merge nodes of your mesh:
        -
      1. From the \b Modification choose \b Transformation and from its +
      2. From the \b Modification choose \b Transformation and from its sub-menu select the Merge nodes item. The following dialog box shall appear:
      3. - +
        \image html mergenodes_auto.png
          @@ -21,13 +22,16 @@ shall appear: processed.
        • \b Tolerance is a maximum distance between nodes sufficient for merging.
        • +
        • Exclude Groups group box allows to ignore the nodes which +belong to the specified mesh groups.
      4. Automatic mode:
        • In the \b Automatic Mode all Nodes within the indicated tolerance -will be merged.
        • +will be merged. The nodes which belong to the groups specified in the +Exclude Groups will be not taken into account.

      5. If the \b Manual Mode is selected, additional controls are available: @@ -44,8 +48,9 @@ viewer with pressed "Shift" key.
      6. Select all checkbox selects all groups.
+
\image html mergenodes.png - +
  • Edit selected group list allows editing the selected group: diff --git a/doc/salome/gui/SMESH/input/mesh_infos.doc b/doc/salome/gui/SMESH/input/mesh_infos.doc index 7b855c42c..919f6768e 100644 --- a/doc/salome/gui/SMESH/input/mesh_infos.doc +++ b/doc/salome/gui/SMESH/input/mesh_infos.doc @@ -1,62 +1,67 @@ /*! -\page mesh_infos_page Mesh infos +\page mesh_infos_page Mesh Information -\n There are three information boxes: Standard Mesh -Infos, Advanced Mesh Infos and Mesh Element Info. +The user can obtain an information about the selected mesh object +(mesh, sub-mesh or group) using Mesh Information dialog box. -
    -\anchor standard_mesh_infos_anchor -

    Standard Mesh Infos

    - -The Standard Mesh Infos box gives only the information on the -number of elements of maximum dimension and the number of nodes in the -mesh. However, from this Info you can learn about groups selected on -this mesh. -\n To view the Standard Mesh Infos, select your mesh or submesh -in the Object Browser and select Standard Mesh Infos -from the \b Mesh menu or click "Standard Mesh Infos" button -in the toolbar. - -\image html image49.png -
    "Standard Mesh Infos" button
    - -The following information will be displayed: - -\image html a-standmeshinfo.png +The Mesh Information dialog box provides two tab pages: +- Base Info - to show base information about selected mesh +object +- Element Info - to show detail information about selected mesh +node or element. -
    \anchor advanced_mesh_infos_anchor -

    Advanced Mesh Infos

    +

    Base Info

    -The Advanced Mesh Infos box gives more information about the mesh, -including the total number of faces and volumes and their geometrical -types. -\n To view the Advanced Mesh Infos, select your mesh or submesh -in the Object Browser and select Advanced Mesh Infos -from the \b Mesh menu or click "Advanced Mesh Infos" button -in the toolbar. +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. + +To view the Mesh Information, select your mesh, sub-mesh or +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 image50.gif -
    "Advanced Mesh Infos" button
    +\image html image49.png +
    "Mesh Information" button
    The following information will be displayed: \image html advanced_mesh_infos.png +
    "Base Info" page
    -
    \anchor mesh_element_info_anchor -

    Mesh Element Info

    +

    Mesh Element Information

    -The Mesh Element Info dialog box gives basic information about the type, coordinates and connectivity of the selected mesh node or element. -\n It is possible to input the Element ID or to select the Element in -the Viewer. +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. -\image html eleminfo1.png +To view the Mesh Element Information, select your mesh, sub-mesh or +group in the Object Browser and invoke Mesh Element Information +item from the \b Mesh menu or click "Mesh Element Information" button +in the toolbar. + +\image html elem_info.png +
    "Mesh Element Information" button
    +The following information will be displayed: + +\image html eleminfo1.png +
    "Element Info" page, node
    +
    \image html eleminfo2.png +
    "Element Info" page, element
    + +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 +the 3D viewer. -In case you get Mesh Infos via a TUI script the information is displayed in Python Console. -See the \ref tui_viewing_mesh_infos "TUI Example", +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". -*/ \ No newline at end of file +*/ + diff --git a/doc/salome/gui/SMESH/input/mesh_through_point.doc b/doc/salome/gui/SMESH/input/mesh_through_point.doc index cd0d68ea9..968bfbc0b 100644 --- a/doc/salome/gui/SMESH/input/mesh_through_point.doc +++ b/doc/salome/gui/SMESH/input/mesh_through_point.doc @@ -1,34 +1,37 @@ /*! -\page mesh_through_point_page Mesh through point +\page mesh_through_point_page Moving nodes -\n In mesh you can define a node at a certain point either by creation -of a new node, by movement of the node closest to the point or by +\n In mesh you can define a node at a certain point either +by movement of the node closest to the point or by movement of any node to the point. -To create a mesh passing through a point: +To displace a node:
      -
    1. From the \b Modification menu choose the Mesh through point item or -click "Mesh to pass through a point" button in the toolbar. +
    2. From the \b Modification menu choose the Move node item or +click "Move Node" button in the toolbar. -\image html mesh_node_to_point.png -
      "Mesh to pass through a point" button
      +\image html image67.png +
      "Move Node" button
      The following dialog box shall appear: \image html meshtopass.png
    3. -
    4. Enter the coordinates of the point.
    5. -
    6. Choose one of several methods: you can either \b Create a new node at -the indicated point or Move the existing node to the point. In the -latter case you can check in Automatic search of the closest node or -select the necessary node manually. \b Preview check-box allows to see -the results of the operation.
    7. -
    8. Click the \b Apply or \b OK button.
    9. +
    10. Enter the coordinates of the destination point.
    11. +
    12. Check in Find closest to destination option or +select the necessary node manually (X, Y, Z, dX, dY, dZ fields allow +to see original coordinates and displacement of the node to move). +\b Preview check-box allows to see the results of the operation.
    13. +
    14. Click the \b Apply or Apply and Close button.
    +\image html moving_nodes1.png "The initial mesh" + +\image html moving_nodes2.png "The modified mesh" +
    See Also a sample TUI Script of a -\ref tui_mesh_through_point "Mesh through point" operation. +\ref tui_moving_nodes "Moving Nodes" operation. */ \ No newline at end of file diff --git a/doc/salome/gui/SMESH/input/minimum_angle.doc b/doc/salome/gui/SMESH/input/minimum_angle.doc index af631b0ec..4236d6562 100644 --- a/doc/salome/gui/SMESH/input/minimum_angle.doc +++ b/doc/salome/gui/SMESH/input/minimum_angle.doc @@ -10,7 +10,8 @@ element (triangle or quadrangle).
    1. Display your mesh in the viewer.
    2. -
    3. Choose Controls > Minimum angle or click "Minimum Angle" button. +
    4. Choose Controls > Face Controls > Minimum angle or click +"Minimum Angle" button. \image html image38.png
      "Minimum Angle" button
      diff --git a/doc/salome/gui/SMESH/input/modifying_meshes.doc b/doc/salome/gui/SMESH/input/modifying_meshes.doc index 05180eb4b..ddddfad50 100644 --- a/doc/salome/gui/SMESH/input/modifying_meshes.doc +++ b/doc/salome/gui/SMESH/input/modifying_meshes.doc @@ -18,7 +18,9 @@ elements of the mesh.
    5. its elements.
    6. \subpage rotation_page "Rotate" by the indicated axis and angle the mesh or some of its elements.
    7. -
    8. \subpage scale_page "Scale Transform" the mesh or some of its elements.
    9. +
    10. \subpage scale_page "Scale Transform" the mesh or some of its +elements.
    11. +
    12. \subpage double_nodes_page "Duplicate nodes".
    13. Create a \subpage symmetry_page "symmetrical copy" of the mesh through a point or a vector of symmetry.
    14. Unite meshes by \subpage sewing_meshes_page "sewing" free borders, @@ -27,10 +29,8 @@ conform free borders, border to side or side elements.
    15. within the indicated tolerance.
    16. \subpage merging_elements_page "Merge Elements", considered coincident within the indicated tolerance.
    17. -
    18. \subpage moving_nodes_page "Move Nodes" to an arbitrary location +
    19. \subpage mesh_through_point_page "Move Nodes" to an arbitrary location with consequent transformation of all adjacent elements and edges.
    20. -
    21. \subpage mesh_through_point_page "Make node at a point", existing -or created anew.
    22. \subpage diagonal_inversion_of_elements_page "Invert an edge" between neighboring triangles.
    23. \subpage uniting_two_triangles_page "Unite two triangles".
    24. \subpage uniting_set_of_triangles_page "Unite several adjacent triangles".
    25. @@ -47,8 +47,7 @@ of the selected node or edge.
    26. Apply \subpage pattern_mapping_page "pattern mapping".
    27. \subpage convert_to_from_quadratic_mesh_page "Convert regular mesh to quadratic", or vice versa.
    28. -
    29. \subpage make_2dmesh_from_3d_page "Create 2D mesh from 3D".
    30. - +
    31. \subpage make_2dmesh_from_3d_page "Generate boundary elements".
    32. \note It is possible to use the variables defined in the SALOME \b NoteBook diff --git a/doc/salome/gui/SMESH/input/moving_nodes.doc b/doc/salome/gui/SMESH/input/moving_nodes.doc deleted file mode 100644 index d44ddc249..000000000 --- a/doc/salome/gui/SMESH/input/moving_nodes.doc +++ /dev/null @@ -1,36 +0,0 @@ -/*! - -\page moving_nodes_page Moving nodes - -\n In MESH you can change the location of any node of your mesh. In -this case all adjacent elements (edges) will be also transformed right -after the displaced node. - -To displace a node: -
        -
      1. From the \b Modification menu choose the Move node item or -click "Move Node" button in the toolbar. - -\image html image67.png -
        "Move Node" button
        - -The following dialog box shall appear: - -\image html movenodes.png - -
      2. -
      3. Enter the ID of the required node in the Node ID field or -select this node in the 3D viewer. The coordinates of your node will -be automatically displayed in the \b Coordinates set of fields.
      4. -
      5. Set new coordinates for your node in the \b Coordinates set of fields.
      6. -
      7. Click the \b Apply or Apply and Close button.
      8. -
      - -\image html moving_nodes1.png "The initial mesh" - -\image html moving_nodes2.png "The node has been moved, transforming all adjacent edges" - -
      See Also a sample TUI Script of a -\ref tui_moving_nodes "Moving Nodes" operation. - -*/ \ No newline at end of file diff --git a/doc/salome/gui/SMESH/input/netgen_2d_3d_hypo.doc b/doc/salome/gui/SMESH/input/netgen_2d_3d_hypo.doc index bbb7c59ff..4690bf966 100644 --- a/doc/salome/gui/SMESH/input/netgen_2d_3d_hypo.doc +++ b/doc/salome/gui/SMESH/input/netgen_2d_3d_hypo.doc @@ -5,11 +5,9 @@ Netgen 2D and Netgen 3D hypotheses work only with Netgen 1D-2D and Netgen 1D-2D-3D algorithms. These algorithms do not require definition of lower-level hypotheses and algorithms (2D and 1D for -meshing 3D objects and 1D for meshing 2D objects). They prove to be -useful if lower-level meshing is homogeneous for all wires and faces -of the meshed object. +meshing 3D objects and 1D for meshing 2D objects). -\image html netgen2d.png +\image html netgen2d3d.png - Name - allows to define the name for the algorithm (Netgen 2D (or 3D) Parameters by default). @@ -32,7 +30,18 @@ not possible. - Optimize - if this box is checked in, the algorithm will try to create regular (possessing even sides) elements. -\image html netgen3d_simple.png +\image html netgen3d_local_size.png + +- Local sizes - allows to define size of elements on and +around specified geometrical edges and vertices. To define the local +size it is necessary to select a geometrical edge or vertex in the +object browser or in the viewer, and to click On Edge or On +Vertex correspondingly. Name of the geometrical object and +a default Value will be added in the table where the +Value can be changed. +- Remove - deletes a selected row from the table. + +\image html netgen2d3d_simple.png Netgen 2D simple parameters and Netgen 3D simple parameters allow defining the size of elements for each @@ -42,8 +51,8 @@ dimension. - Number of Segments has the same sense as \ref number_of_segments_anchor "Number of segments" hypothesis with equidistant distribution. -- Average Length has the same sense as \ref -average_length_anchor "Average Length" hypothesis. +- Local Length has the same sense as \ref +average_length_anchor "Local Length" hypothesis. \b 2D group allows defining the size of 2D elements - Length from edges if checked in, acts like \ref diff --git a/doc/salome/gui/SMESH/input/pattern_mapping.doc b/doc/salome/gui/SMESH/input/pattern_mapping.doc index 1a48a4644..ef7f8ba66 100644 --- a/doc/salome/gui/SMESH/input/pattern_mapping.doc +++ b/doc/salome/gui/SMESH/input/pattern_mapping.doc @@ -5,33 +5,31 @@

      About patterns

      The pattern describes a mesh to generate: positions of nodes within a -geometrical domain and nodal connectivity of elements. As well, a -pattern specifies the so-called key-points, i.e. nodes that will be -located at geometrical vertices. Pattern description is stored in +geometrical domain and nodal connectivity of elements. A +pattern also specifies the so-called key-points, i.e. the nodes that will be +located at geometrical vertices. The pattern description is stored in \.smp file. The smp file contains 4 sections: --# The first line holds the total number of the pattern nodes (N). --# The next N lines describe nodes coordinates. Each line holds 2 -coordinates of a node for 2D pattern or 3 cordinates for 3D pattern. -Note, that for 3D pattern only relateive values in range [0;1] are -valid for coordinates of the nodes. --# A key-points line: indices of nodes to be mapped on geometrical -vertices (for 2D pattern only). An index n refers to a node described -on an n-th line of section 2. The first node index is zero. For 3D -pattern key points are not specified. --# The rest lines describe nodal connectivity of elements, one line -for an element. A line holds indices of nodes forming an element. An -index n refers to a node described on an n-th line of the section -2. The first node index is zero. There must be 3 or 4 indices on a -line for 2D pattern (only 2d elements are allowed) and 4, 5, 6 or 8 -indices for 3D pattern (only 3d elements are allowed). - -The 2D pattern must contain at least one element and at least one -key-point. All key-points must lay on boundaries. - -The 3D pattern must contain at least one element. +-# The first line indicates the total number of pattern nodes (N). +-# The next N lines describe nodes coordinates. Each line contains 2 +node coordinates for a 2D pattern or 3 node cordinates for a 3D pattern. +Note, that node coordinates of a 3D pattern can be defined only by relative values in range [0;1]. +-# The key-points line contains the indices of the nodes to be mapped on geometrical +vertices (for a 2D pattern only). Index n refers to the node described +on the n-th line of section 2. The index of the first node zero. For a 3D pattern the key points are not specified. +-# The remaining lines describe nodal connectivity of elements, one line +for each element. Each line holds indices of nodes forming an element. +Index n refers to the node described on the n-th line of section 2. +The first node index is zero. There must be 3 or 4 indices on each +line for a 2D pattern (only 2d elements are allowed) and 4, 5, 6 or 8 +indices for a 3D pattern (only 3d elements are allowed). + +A 2D pattern must contain at least one element and at least one +key-point. All key-points must lie on boundaries. + +A 3D pattern must contain at least one element. An example of a simple 2D pattern smp file: @@ -60,7 +58,7 @@ An example of a simple 2D pattern smp file: 8 1 2 \endcode -The image below provides a preview of above described pattern: +The image below provides a preview of the above pattern: \image html pattern2d.png @@ -99,91 +97,120 @@ From the \b Modification menu choose the Pattern Mapping item or click \image html image98.png
      "Pattern mapping" button
      -The following dialog box shall appear: +The following dialog box will appear: + +\n For a 2D pattern \image html patternmapping1.png -
      2D Pattern Mapping dialog box
      +In this dialog you should specify: + +
        +
      • \b Pattern, which can be loaded from .smp pattern file previously +created manually or generated automatically from an existing mesh or submesh.
      • +
      • \b Face with the number of vertices equal to the number of + key-points in the pattern; the number of key-points on internal + boundaries of the pattern must also be equal to the number of vertices + on internal boundaries of the face;
      • +
      • \b Vertex to which the first key-point should be mapped;
      • +Alternatively, it is possible to select Refine selected mesh elements +checkbox and apply the pattern to +
      • Mesh Face instead of a geometric Face
      • +
      • and select \b Node instead of vertex.
      • + +Additionally it is possible to: +
      • Reverse the order of key-points By default, the vertices of + a face are ordered counterclockwise.
      • +
      • Enable to Create polygons near boundary
      • +
      • and Create polyhedrons near boundary
      • +
      + +\n For a 3D pattern \image html patternmapping2.png -
      3D Pattern Mapping dialog box
      +In this dialog you should specify: +
        +
      • \b Pattern, which can be loaded from .smp pattern file previously +created manually or generated automatically from an existing mesh or submesh.
      • +
      • A 3D block (Solid) object;
      • +
      • Two vertices that specify the order of nodes in the resulting mesh.
      • +Alternatively, it is possible to select Refine selected mesh elements +checkbox and apply the pattern to +
      • One or several Mesh volumes instead of a geometric 3D +object
      • +
      • and select two /b Nodes instead of vertices.
      • +Additionally it is possible to: +
      • Enable to Create polygons near boundary
      • +
      • and Create polyhedrons near boundary
      • +
      + +\n Automatic Generation + +To generate a pattern automatically from an existing mesh or submesh, +click \b New button. + +The following dialog box will appear: -To apply a pattern to a geometrical object, you should specify: +\image html a-patterntype1.png --# For 2D pattern - - A face having the number of vertices equal to the number of - key-points in the pattern; the number of key-points on internal - boundaries of a pattern must also be equal to the number of vertices - on internal boundaries of a face; - - A vertex to which the first key-point should be mapped; - - Reverse or not the order of key-points. (The order of vertices of - a face is counterclockwise looking from outside). --# For 3D pattern - - 3D block (Solid) object; - - Two vertices that specify the order of nodes in the resulting - mesh. - -Then you either load a .smp pattern file previously created manually -by clicking on the "Load pattern" button, or click on the \b -New button for automatic generation of the pattern. - -For an automatic generation you just specify a geometrical face (for -2D) or solid (for 3d) having a mesh built on it. Mesh nodes lying on -face vertices become key-points of 2D pattern. Additionally, for 2D -pattern you may choose the way of getting nodes coordinates by -projecting nodes on the face instead of using -"positions on face" generated by mesher (if there is any). Faces -having a seam edge can't be used for automatic pattern creation. - -When creating a pattern from an existing mesh, there are two possible -cases: - -- A sub-mesh on face/solid is selected. A pattern is created from the 2d/3d -elements bound to a face/solid by mesher. For 2D pattern, node coordinates are either -"positions on face" computed by mesher, or coordinates got by node -projection on a geometrical surface, according to the user choice. For -3D pattern, nodes coordinates correspond to the nodes computed by mesher. -- A mesh where the main shape is a face/solid, is selected. A pattern is -created from all the 2d/3d elements in a mesh. In addition, for 2D -pattern, if all mesh elements are build by mesher, the user can select -the way of getting nodes coordinates, else all nodes are projected on -a face surface. +In this dialog you should specify: -\image html a-patterntype.png +
        +
      • Mesh or Submesh, which is a meshed geometrical face (for a +2D pattern) or a meshed solid (for a 3D pattern). Mesh nodes lying on +the face vertices become key-points of the pattern.
      • +
      • A custom Pattern Name
      • +
      • Additionally, for a 2D pattern you may choose to +Project nodes on the face to get node coordinates instead of using +"positions on face" generated by the mesher (if there is any). The faces +having a seam edge cannot be used for automatic pattern creation.
      • +
      -
      2D Pattern Creation dialog box
      +When a pattern is created from an existing mesh, two cases are possible: -\image html a-patterntype1.png +- A sub-mesh on a face/solid is selected. The pattern is created from the 2d/3d +elements bound to the face/solid by the mesher. For a 2D pattern, the node coordinates are either +"positions on face" computed by the mesher, or coordinates got by node +projection on a geometrical surface, according to the user choice. For +a 3D pattern, the node coordinates correspond to the nodes computed by +the mesher. +- A mesh, where the main shape is a face/solid, is selected. The pattern is +created from all 2d/3d elements in a mesh. In addition, if all mesh +elements of a 2D pattern are built by the mesher, the user can select +how to get node coordinates, otherwise all nodes are projected on +a face surface. -
      3D Pattern Creation dialog box

      Mapping algorithm

      -The mapping algorithm for 2D case is as follows: - -- Key-points are set in the order that they are encountered when - walking along a pattern boundary so that elements are on the left. The - first key-point is preserved. -- Find geometrical vertices corresponding to key-points by vertices - order in a face boundary; here, "Reverse order of key-points" flag is - taken into account. \image html image95.gif -- Boundary nodes of a pattern are mapped onto edges of a face: a - node located between certain key-points on a pattern boundary is - mapped on a geometrical edge limited by corresponding geometrical - vertices. Node position on an edge reflects its distance from two - key-points. \image html image96.gif -- Coordinates of a non-boundary node in a parametric space of a face - are defined as following. In a parametric space of a pattern, a node - lays at the intersection of two iso-lines, each of which intersects a - pattern boundary at least at two points. Knowing mapped positions of - boundary nodes, we find where isoline-boundary intersection points are - mapped to, and hence we can find mapped isolines direction and then, - two node positions on two mapped isolines. The eventual mapped - position of a node is found as an average of positions on mapped - isolines. \image html image97.gif - -For 3D case the algorithm is similar. +The mapping algorithm for a 2D case is as follows: + +- The key-points are set counterclockwise in the order corresponding + to their location on the pattern boundary. The first key-point is preserved. +- The geometrical vertices corresponding to the key-points are found + on face boundary. Here, "Reverse order of key-points" flag is set. +\image html image95.gif +- The boundary nodes of the pattern are mapped onto the edges of the face: a + node located between two key-points on the pattern boundary is + mapped on the geometrical edge limited by the corresponding geometrical + vertices. The node position on the edge depends on its distance from the + key-points. +\image html image96.gif +- The cordinates of a non-boundary node in the parametric space of the face + are defined in the following way. In the parametric space of the + pattern, the node lies at the intersection of two iso-lines. Both + of them intersect the pattern boundary at two + points at least. If the mapped positions of boundary nodes are known, it is + possible to find, where the points at the intersection of isolines + and boundaries are mapped. Then it is possible to find + the direction of mapped isolinesection and, filally, the poitions of + two nodes on two mapped isolines. The eventual mapped + position of the node is found as an average of the positions on mapped + isolines. +\image html image97.gif + +The 3D algorithm is similar. See Also a sample TUI Script of a \ref tui_pattern_mapping "Pattern Mapping" operation. diff --git a/doc/salome/gui/SMESH/input/removing_nodes_and_elements.doc b/doc/salome/gui/SMESH/input/removing_nodes_and_elements.doc index 6cd891573..0a48ee65e 100644 --- a/doc/salome/gui/SMESH/input/removing_nodes_and_elements.doc +++ b/doc/salome/gui/SMESH/input/removing_nodes_and_elements.doc @@ -6,6 +6,7 @@
      • \ref removing_nodes_anchor "Nodes"
      • +
      • \ref removing_orphan_nodes_anchor "Orphan Nodes"
      • \ref removing_elements_anchor "Elements"
      • \ref clear_mesh_anchor "Clear Mesh Data"
      @@ -18,11 +19,11 @@
      1. Select your mesh in the Object Browser or in the 3D viewer.
      2. -
      3. From the Modification menu choose Remove and from the associated -submenu select the Remove nodes, or just click "Remove nodes" +
      4. From the Modification menu choose Remove and from the associated +submenu select the Nodes, or just click "Remove nodes" button in the toolbar. -\image html image88.gif +\image html remove_nodes_icon.png
        "Remove nodes" button
        The following dialog box will appear: @@ -46,6 +47,30 @@ about filters in the \ref selection_filter_library_page "Selection filter librar \note Be careful while removing nodes because if you remove a definite node of your mesh all adjacent elements will be also deleted. +
        +\anchor removing_orphan_nodes_anchor +

        Removing orphan nodes

        + +There is a quick way to remove all orphan (free) nodes. + +To remove orphan nodes: +
          +
        1. Select your mesh in the Object Browser or in the 3D viewer.
        2. + +
        3. From the Modification menu choose Remove and from the associated +submenu select Orphan Nodes, or just click "Remove orphan nodes" +button in the toolbar. + +\image html remove_orphan_nodes_icon.png +
          "Remove orphan nodes" button
          + +The following Warning message box will appear: + +\image html removeorphannodes.png + +Confirm nodes removal by pressing "Yes" button. +
        +
        \anchor removing_elements_anchor

        Removing elements

        @@ -54,8 +79,8 @@ node of your mesh all adjacent elements will be also deleted.
        1. Select your mesh in the Object Browser or in the 3D viewer.
        2. -
        3. From the \b Modification menu choose \b Remove and from the -associated submenu select the Remove elements, or just click +
        4. From the Modification menu choose Remove and from the +associated submenu select the Elements, or just click "Remove elements" button in the toolbar. \image html remove_elements_icon.png @@ -94,7 +119,7 @@ about filters in the \ref selection_filter_library_page "Selection filter librar
        5. From the Modification menu choose Remove and from the associated submenu select the Clear Mesh Data, or just click "Clear Mesh Data" button in the toolbar. You can also right-click on the mesh in the -Object Browser and select Clear Mesh Data in the pop-up menu. +Object Browser and select Clear Mesh Data in the pop-up menu.
        \image html mesh_clear.png diff --git a/doc/salome/gui/SMESH/input/selection_filter_library.doc b/doc/salome/gui/SMESH/input/selection_filter_library.doc index 94dd3844c..1f612994f 100644 --- a/doc/salome/gui/SMESH/input/selection_filter_library.doc +++ b/doc/salome/gui/SMESH/input/selection_filter_library.doc @@ -156,6 +156,17 @@ See also a length, which is more, less or equal (within a given Tolerance) to the predefined Threshold Value. See also a \ref length_2d_page "Length 2D quality control". +
      5. +Coplanar faces selects mesh faces neighboring the one selected +by ID in Threshold Value field, if the angle between the +normal to the neighboring face and the normal to the selected face is less then the +angular tolerance (defined in degrees). Selection continues among all neighbor faces of already +selected ones.
        +
      6. +Element Diameter 2D selects triangles and quadrangles combining of the edges and +diagonals with a value of length, which is more, less or equal +(within a given Tolerance) to the predefined Threshold Value. See also a +\ref max_element_length_2d_page "Element Diameter 2D quality control".
      7. @@ -169,6 +180,11 @@ Additional criteria to select mesh Volumes are the following: \ref volume_page "Volume quality control"), which is more, less or equal (within a given Tolerance) to the predefined Threshold Value.
      8. +Element Diameter 3D selects 3D mesh elements combining of the edges and +diagonals with a value of length, which is more, less or equal +(within a given Tolerance) to the predefined Threshold Value. See also a +\ref max_element_length_3d_page "Element Diameter 3D quality control". +
      9. Bad oriented volume selects mesh volumes, which are incorrectly oriented from the point of view of MED convention.
      10. diff --git a/doc/salome/gui/SMESH/input/skew.doc b/doc/salome/gui/SMESH/input/skew.doc index 5235b4ddd..036c70d83 100644 --- a/doc/salome/gui/SMESH/input/skew.doc +++ b/doc/salome/gui/SMESH/input/skew.doc @@ -14,7 +14,8 @@ criterion can be applied to elements composed of 4 and 3 nodes
        1. Display your mesh in the viewer.
        2. -
        3. Choose Controls > Skew or click "Skew" button of the toolbar. +
        4. Choose Controls > Face Controls > Skew or click +"Skew" button of the toolbar. \image html image40.png
          "Skew" button
          diff --git a/doc/salome/gui/SMESH/input/smeshpy_interface.doc b/doc/salome/gui/SMESH/input/smeshpy_interface.doc index e0fe78ec9..8b63ddfa3 100644 --- a/doc/salome/gui/SMESH/input/smeshpy_interface.doc +++ b/doc/salome/gui/SMESH/input/smeshpy_interface.doc @@ -133,9 +133,11 @@ the following links: - \subpage tui_viewing_meshes_page - \subpage tui_defining_hypotheses_page - \subpage tui_quality_controls_page +- \subpage tui_filters_page - \subpage tui_grouping_elements_page - \subpage tui_modifying_meshes_page - \subpage tui_transforming_meshes_page - \subpage tui_notebook_smesh_page +- \subpage tui_measurements_page */ diff --git a/doc/salome/gui/SMESH/input/smeshpypkg.doc b/doc/salome/gui/SMESH/input/smeshpypkg.doc new file mode 100644 index 000000000..06bf94a23 --- /dev/null +++ b/doc/salome/gui/SMESH/input/smeshpypkg.doc @@ -0,0 +1,14 @@ +/*! + +\page smeshpypkg_page Programming Interface of the SMESH python package + +Sorry, but the documentation is not available yet in doxygen format. + +Fortunately, a documentation exists in restructured format and then +can be generated here using sphinx, in the expectative of the doxygen +version. + +Please refer to this
          +documentation of the SMESH python packages. + +*/ diff --git a/doc/salome/gui/SMESH/input/split_to_tetra.doc b/doc/salome/gui/SMESH/input/split_to_tetra.doc index 4817a3f2f..4b09b2199 100644 --- a/doc/salome/gui/SMESH/input/split_to_tetra.doc +++ b/doc/salome/gui/SMESH/input/split_to_tetra.doc @@ -37,7 +37,7 @@ volumes of the currently displayed mesh or submesh.
        5. \b Split hexahedron
            -
          • Into 5 tetrahedra and Into 6 tetrahedra allows to +
          • Into 5 tetrahedra, Into 5 tetrahedra and Into 24 tetrahedra allows to specify the number of tetrahedra a hexahedron will be split into. If the specified method does not allow to get a conform mesh, a generic solution is applied: an additional node is created at the gravity center of a hexahedron, serving an apex of tetrahedra, all quadrangle sides of the hexahedron are split into two triangles each serving a base of a new tetrahedron.
          • diff --git a/doc/salome/gui/SMESH/input/taper.doc b/doc/salome/gui/SMESH/input/taper.doc index d2c4dd2b4..86472eabe 100644 --- a/doc/salome/gui/SMESH/input/taper.doc +++ b/doc/salome/gui/SMESH/input/taper.doc @@ -13,8 +13,8 @@ for elements consisting of 4 nodes.
            1. Display your mesh in the viewer.
            2. -
            3. Choose Controls > Taper or click "Taper" button in -the toolbar. +
            4. Choose Controls > Face Controls > Taper or click +"Taper" button in the toolbar. \image html image36.png
              "Taper" button
              diff --git a/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc b/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc index 1aa91d9d5..1581e7c2f 100644 --- a/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc +++ b/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc @@ -128,7 +128,7 @@ hexa.Compute()
              \anchor tui_average_length -

              Average Length

              +

              Local Length

              \code from geompy import * @@ -549,11 +549,10 @@ mesh.Compute() \endcode \anchor tui_quadrangle_parameters -

              Quadrangle Parameters example

              +

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

              \code -import geompy -import smesh -import StdMeshers +from smesh import * +SetCurrentStudy(salome.myStudy) # Get 1/4 part from the disk face. Box_1 = geompy.MakeBoxDXDYDZ(100, 100, 100) @@ -566,17 +565,112 @@ 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 + +

              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.SetTriaVertex( 8 ) +Quadrangle_Parameters_1.SetQuadType( StdMeshers.QUAD_QUADRANGLE_PREF ) -# Define 1D hypothesis and cmpute the mesh +# Define other hypotheses and algorithms Regular_1D = Mesh_1.Segment() -Nb_Segments_1 = Regular_1D.NumberOfSegments(10) +Nb_Segments_1 = Regular_1D.NumberOfSegments(4) Nb_Segments_1.SetDistrType( 0 ) status = Mesh_1.AddHypothesis(Quadrangle_Parameters_1) Quadrangle_2D = Mesh_1.Quadrangle() -Mesh_1.Compute() + +# 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 + +\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 \n Other meshing algorithms: diff --git a/doc/salome/gui/SMESH/input/tui_filters.doc b/doc/salome/gui/SMESH/input/tui_filters.doc new file mode 100755 index 000000000..6677b2ab5 --- /dev/null +++ b/doc/salome/gui/SMESH/input/tui_filters.doc @@ -0,0 +1,594 @@ +/*! + +\page tui_filters_page Filters usage + +Filters allow picking only the mesh elements satisfying to a +specific condition or a set of conditions. Filters can be used to create +or edit mesh groups, remove elements from the mesh object, control +mesh quality by different parameters, etc. + +Several filters can be combined together by using logical operators \a +AND and \a OR. In addition, applied filter criterion can be reverted +using logical operator \a NOT. + +Mesh filters use the functionality of mesh quality controls to filter +mesh nodes / elements by a specific characteristic (Area, Length, etc). + +This page provides a short description of the existing mesh filters, +describes required parameters and gives simple examples of usage in +Python scripts. + +\sa \ref tui_quality_controls_page + +\section filter_aspect_ratio Aspect ratio + +Filter 2D mesh elements (faces) according to the aspect ratio value: +- element type should be \a smesh.FACE +- 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 + +\sa \ref tui_aspect_ratio + +\section filter_aspect_ratio_3d Aspect ratio 3D + +Filter 3D mesh elements (volumes) according to the aspect ratio value: +- element type is \a smesh.VOLUME +- 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( algo=smesh.NETGEN ) +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 + +\sa \ref tui_aspect_ratio_3d + +\section filter_warping_angle Warping angle + +Filter 2D mesh elements (faces) according to the warping angle value: +- element type is \a smesh.FACE +- 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 + +\sa \ref tui_warping + +\section filter_minimum_angle Minimum angle + +Filter 2D mesh elements (faces) according to the minimum angle value: +- element type is \a smesh.FACE +- 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, smesh.FT_MoreThan, 75) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces with minimum angle > 75:", len(ids) +\endcode + +\sa \ref tui_minimum_angle + +\section filter_taper Taper + +Filter 2D mesh elements (faces) according to the taper value: +- element type is \a smesh.FACE +- 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 + +\sa \ref tui_taper + +\section filter_skew Skew + +Filter 2D mesh elements (faces) according to the skew value: +- element type is \a smesh.FACE +- 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 + +\sa \ref tui_skew + +\section filter_area Area + +Filter 2D mesh elements (faces) according to the area value: +- element type is \a smesh.FACE +- 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 + +\sa \ref tui_area + +\section filter_volume Volume + +Filter 3D mesh elements (volumes) according to the volume value: +- element type is \a smesh.VOLUME +- functor type is \a smesh.FT_Volume3D +- threshold is floating point value (volume) + +\code +# create mesh with volumes +from SMESH_mechanic import * +mesh.Tetrahedron( algo=smesh.NETGEN ) +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 + +\sa \ref tui_volume + +\section filter_free_borders Free borders + +Filter 1D mesh elements (edges) which represent free borders of a mesh: +- element type is \a smesh.EDGE +- 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 + +\sa \ref tui_free_borders + +\section filter_free_edges Free edges + +Filter 2D mesh elements (faces) consisting of edges belonging to one +element of mesh only: +- element type is \a smesh.FACE +- 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 + +\sa \ref tui_free_edges + +\section filter_free_nodes Free nodes + +Filter free nodes: +- element type is \a smesh.NODE +- 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.EDGE, smesh.FT_FreeNodes) +ids = mesh.GetIdsFromFilter(filter) +print "Number of free nodes:", len(ids) +\endcode + +\sa \ref tui_free_nodes + +\section filter_free_faces Free faces + +Filter free faces: +- element type is \a smesh.FACE +- 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.EDGE, smesh.FT_FreeFaces) +ids = mesh.GetIdsFromFilter(filter) +print "Number of free faces:", len(ids) +\endcode + +\sa \ref tui_free_faces + +\section filter_borders_multiconnection Borders at multi-connection + +Filter border 1D mesh elements (edges) according to the specified number of +connections (faces belonging the border edges) +- element type is \a smesh.EDGE +- 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 + +\sa \ref tui_borders_at_multiconnection + +\section filter_borders_multiconnection_2d Borders at multi-connection 2D + +Filter 2D mesh elements (faces) which consist of edges belonging +to the specified number of mesh elements +- element type is \a smesh.FACE +- 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 + +\sa \ref tui_borders_at_multiconnection_2d + +\section filter_length Length + +Filter 1D mesh elements (edges) according to the edge length value: +- element type should be \a smesh.EDGE +- 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 + +\sa \ref tui_length_1d + +\section filter_length_2d Length 2D + +Filter 2D mesh elements (faces) corresponding to the maximum length. +value of its edges: +- element type should be \a smesh.FACE +- 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 + +\sa \ref tui_length_2d + +\section filter_max_element_length_2d Element Diameter 2D + +Filter 2D mesh elements (faces) corresponding to the maximum length +value of its edges and diagonals: +- element type should be \a smesh.FACE +- 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 + +\sa \ref tui_max_element_length_2d + +\section filter_max_element_length_3d Element Diameter 3D + +Filter 3D mesh elements (volumes) corresponding to the maximum length +value of its edges and diagonals: +- element type should be \a smesh.VOLUME +- 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( algo=smesh.NETGEN ) +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 + +\sa \ref tui_max_element_length_3d + +\section filter_belong_to_geom Belong to Geom + +Filter mesh entities (nodes or elements) which all nodes lie on the +shape defined by threshold value: +- element type can be any entity type, from \a smesh.NODE to \a smesh.VOLUME +- 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 + +\section filter_lying_on_geom Lying on Geom + +Filter mesh entities (nodes or elements) at least one node of which lies on the +shape defined by threshold value: +- element type can be any entity type, from \a smesh.NODE to \a smesh.VOLUME +- 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 + +\section filter_belong_to_plane Belong to Plane + +Filter mesh entities (nodes or elements) which all nodes belong to the +plane defined by threshold value with the given tolerance: +- element type can be: \a smesh.NODE, \a smesh.EDGE, \a smesh.FACE +- functor type should be \a smesh.FT_BelongToPlane +- 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 + +\section filter_belong_to_cylinder Belong to Cylinder + +Filter mesh entities (nodes or elements) which all nodes belong to the +cylindrical face defined by threshold value with the given tolerance: +- element type can be: \a smesh.NODE, \a smesh.EDGE, \a smesh.FACE +- functor type should be \a smesh.FT_BelongToCylinder +- 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 + +\section filter_belong_to_surface Belong to Surface + +Filter mesh entities (nodes or elements) which all nodes belong to the +arbitrary surface defined by threshold value with the given tolerance: +- element type can be: \a smesh.NODE, \a smesh.EDGE, \a smesh.FACE +- functor type should be \a smesh.FT_BelongToGenSurface +- 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 + +\section filter_range_of_ids Range of IDs + +Filter mesh entities elements (nodes or elements) according to the +specified identifiers range: +- element type can be any entity type, from \a smesh.NODE to \a smesh.VOLUME +- 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 + +\section filter_bad_oriented_volume Badly oriented volume + +Filter 3D mesh elements (volumes), which are incorrectly oriented from +the point of view of MED convention. +- element type should be \a smesh.VOLUME +- functor type is \a smesh.FT_BadOrientedVolume +- threshold is not required + +\code +# create mesh with volumes +from SMESH_mechanic import * +mesh.Tetrahedron( algo=smesh.NETGEN ) +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 + +\section filter_linear_or_quadratic Linear / quadratic + +Filter linear / quadratic mesh elements: +- element type should be any element type, e.g.: \a smesh.EDGE, \a smesh.FACE, \a smesh.VOLUME +- functor type is \a smesh.FT_LinearOrQuadratic +- threshold is not required +- 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 + +\section filter_group_color Group color + +Filter mesh entities, belonging to the group with the color defined by the threshold value. +- element type can be any entity type, from \a smesh.NODE to \a smesh.VOLUME +- 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 + +\section filter_geom_type Geometry type + +Filter mesh elements by the geometric type defined with the threshold +value. The list of available geometric types depends on the element +entity type. +- element type should be any element type, e.g.: \a smesh.EDGE, \a smesh.FACE, \a smesh.VOLUME +- 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( algo=smesh.NETGEN ) +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 + +*/ diff --git a/doc/salome/gui/SMESH/input/tui_grouping_elements.doc b/doc/salome/gui/SMESH/input/tui_grouping_elements.doc index b77edd21e..1aa73a484 100644 --- a/doc/salome/gui/SMESH/input/tui_grouping_elements.doc +++ b/doc/salome/gui/SMESH/input/tui_grouping_elements.doc @@ -1,4 +1,4 @@ - /*! +/*! \page tui_grouping_elements_page Grouping Elements @@ -19,7 +19,11 @@ 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 -aGroup = mesh.MakeGroupByIds("Area > 100", smesh.FACE, anIds) +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 diff --git a/doc/salome/gui/SMESH/input/tui_measurements.doc b/doc/salome/gui/SMESH/input/tui_measurements.doc new file mode 100644 index 000000000..aabf0b317 --- /dev/null +++ b/doc/salome/gui/SMESH/input/tui_measurements.doc @@ -0,0 +1,84 @@ +/*! + +\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 + +\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 + +*/ diff --git a/doc/salome/gui/SMESH/input/tui_modifying_meshes.doc b/doc/salome/gui/SMESH/input/tui_modifying_meshes.doc index 2e8f75291..fe0da8e61 100644 --- a/doc/salome/gui/SMESH/input/tui_modifying_meshes.doc +++ b/doc/salome/gui/SMESH/input/tui_modifying_meshes.doc @@ -282,35 +282,40 @@ else: print "KO Elements removing." \endcode
              -\anchor tui_renumbering_nodes_and_elements -

              Renumbering Nodes and Elements

              +\anchor tui_removing_orphan_nodes +

              Removing Orphan Nodes

              \code import SMESH_mechanic mesh = SMESH_mechanic.mesh -mesh.RenumberNodes() - -mesh.RenumberElements() +# 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
              -\anchor tui_moving_nodes -

              Moving Nodes

              +\anchor tui_renumbering_nodes_and_elements +

              Renumbering Nodes and Elements

              \code import SMESH_mechanic mesh = SMESH_mechanic.mesh -# move node #38 -mesh.MoveNode(38, 20., 10., 0.) +mesh.RenumberNodes() + +mesh.RenumberElements() \endcode
              -\anchor tui_mesh_through_point -

              Mesh through point

              +\anchor tui_moving_nodes +

              Moving Nodes

              \code from geompy import * @@ -344,16 +349,11 @@ n = mesh.FindNodeClosestTo( -1,-1,-1 ) if not n == node000: raise "FindNodeClosestTo() returns " + str( n ) + " != " + str( node000 ) -# check if any node will be found for a point inside a box -n = mesh.FindNodeClosestTo( 100, 100, 100 ) -if not n > 0: - raise "FindNodeClosestTo( 100, 100, 100 ) fails" - # move node000 to a new location x,y,z = -10, -10, -10 -n = mesh.MeshToPassThroughAPoint( x,y,z ) -if not n == node000: - raise "FindNodeClosestTo() returns " + str( n ) + " != " + str( node000 ) +n = mesh.MoveNode( n,x,y,z ) +if not n: + raise "MoveNode() returns " + n # check the coordinates of the node000 xyz = mesh.GetNodeXYZ( node000 ) diff --git a/doc/salome/gui/SMESH/input/tui_quality_controls.doc b/doc/salome/gui/SMESH/input/tui_quality_controls.doc index 57d52c69e..fc496dcde 100644 --- a/doc/salome/gui/SMESH/input/tui_quality_controls.doc +++ b/doc/salome/gui/SMESH/input/tui_quality_controls.doc @@ -2,9 +2,7 @@ \page tui_quality_controls_page Quality Controls -
              -\anchor tui_free_borders -

              Free Borders

              +\section tui_free_borders Free Borders \code import salome @@ -48,9 +46,7 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_borders_at_multiconnection -

              Borders at Multiconnection

              +\section tui_borders_at_multiconnection Borders at Multiconnection \code import salome @@ -97,9 +93,7 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_length_1d -

              Length 1D

              +\section tui_length_1d Length 1D \code import salome @@ -145,9 +139,7 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_free_edges -

              Free Edges

              +\section tui_free_edges Free Edges \code import SMESH_mechanic @@ -189,9 +181,7 @@ for i in range(len(aBorders)): salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_free_nodes -

              Free Nodes

              +\section tui_free_nodes Free Nodes \code import salome @@ -242,10 +232,7 @@ print "" salome.sg.updateObjBrowser(1) \endcode - -
              -\anchor tui_free_faces -

              Free Faces

              +\section tui_free_faces Free Faces \code import salome @@ -322,10 +309,7 @@ aGroup.Add(aFaceIds) salome.sg.updateObjBrowser(1) \endcode - -
              -\anchor tui_length_2d -

              Length 2D

              +\section tui_length_2d Length 2D \code import salome @@ -372,9 +356,7 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_borders_at_multiconnection_2d -

              Borders at Multiconnection 2D

              +\section tui_borders_at_multiconnection_2d Borders at Multiconnection 2D \code import salome @@ -421,9 +403,7 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_area -

              Area

              +\section tui_area Area \code import SMESH_mechanic @@ -456,9 +436,7 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_taper -

              Taper

              +\section tui_taper Taper \code import SMESH_mechanic @@ -491,9 +469,7 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_aspect_ratio -

              Aspect Ratio

              +\section tui_aspect_ratio Aspect Ratio \code import SMESH_mechanic @@ -526,9 +502,7 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_minimum_angle -

              Minimum Angle

              +\section tui_minimum_angle Minimum Angle \code import SMESH_mechanic @@ -562,9 +536,7 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_warping -

              Warping

              +\section tui_warping Warping \code import SMESH_mechanic @@ -598,9 +570,7 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_skew -

              Skew

              +\section tui_skew Skew \code import SMESH_mechanic @@ -633,9 +603,40 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_aspect_ratio_3d -

              Aspect Ratio 3D

              +\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 + +\section tui_aspect_ratio_3d Aspect Ratio 3D \code import SMESH_mechanic_tetra @@ -669,9 +670,7 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -
              -\anchor tui_volume -

              Volume

              +\section tui_volume Volume \code import SMESH_mechanic_tetra @@ -706,4 +705,37 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode +\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 + */ diff --git a/doc/salome/gui/SMESH/input/tui_transforming_meshes.doc b/doc/salome/gui/SMESH/input/tui_transforming_meshes.doc index c55b2a492..22f11886f 100644 --- a/doc/salome/gui/SMESH/input/tui_transforming_meshes.doc +++ b/doc/salome/gui/SMESH/input/tui_transforming_meshes.doc @@ -350,4 +350,238 @@ mesh.Compute() mesh.SewSideElements([69, 70, 71, 72], [91, 92, 89, 90], 8, 38, 23, 58) \endcode +
              +\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 + +
              +\anchor tui_make_2dmesh_from_3d +

              Create boundary elements

              + +\code +# The objective of these samples is to illustrate the following use cases: +# 1) The mesh MESH1 with 3D cells has no or only a part of its skin (2D cells): +# 1.1) Add the 2D skin (missing 2D cells) to MESH1 (what is done now by the algorithm). +# 1.2) Create a new 3D Mesh MESH2 that consists of MESH1 and added 2D skin cells. +# 1.3) Create a new 2D Mesh MESH3 that consists only of 2D skin cells. +# 2) The mesh MESH1 with 3D cells has all its skin (2D cells): +# Create a new 2D Mesh MESH3 that consists only of 2D skin cells. +# +# In all cases an option to create a group containing these 2D skin cells is available. + +from smesh import * + +box = geompy.MakeBoxDXDYDZ(1,1,1) +geompy.addToStudy(box,"box") +boxFace = geompy.SubShapeAll(box, geompy.ShapeType["FACE"])[0] +geompy.addToStudyInFather(box,boxFace,"boxFace") + +MESH1 = Mesh(box,"MESH1") +MESH1.AutomaticHexahedralization() + +init_nb_edges = MESH1.NbEdges() +init_nb_faces = MESH1.NbFaces() +init_nb_volumes = MESH1.NbVolumes() + +# ========================================================================================= +# 1) The mesh MESH1 with 3D cells has no or only a part of its skin (2D cells) +# ========================================================================================= +# remove some faces +all_faces = MESH1.GetElementsByType(SMESH.FACE) +rm_faces = all_faces[:init_nb_faces/5] + all_faces[4*init_nb_faces/5:] +MESH1.RemoveElements(rm_faces) +assert(MESH1.NbFaces() == init_nb_faces-len(rm_faces)) + +# 1.1) Add the 2D skin (missing 2D cells) to MESH1 +# ------------------------------------------------- +# add missing faces +# 1.1.1) to the whole mesh +m,g = MESH1.MakeBoundaryMesh(MESH1) +assert(init_nb_faces == MESH1.NbFaces()) +assert(init_nb_edges == MESH1.NbEdges()) +assert(m) +assert(not g) + +# 1.1.2) to some elements +MESH1.RemoveElements(rm_faces) +MESH1.MakeBoundaryMesh([]) +assert(init_nb_faces != MESH1.NbFaces()) +volumes = MESH1.GetElementsByType(SMESH.VOLUME) +for v in volumes: + MESH1.MakeBoundaryMesh([v]) +assert(init_nb_faces == MESH1.NbFaces()) +assert(init_nb_edges == MESH1.NbEdges()) + +# 1.1.3) to a group of elements +volGroup1 = MESH1.CreateEmptyGroup(SMESH.VOLUME, "volGroup1") +volGroup1.Add( volumes[: init_nb_volumes/2]) +volGroup2 = MESH1.CreateEmptyGroup(SMESH.VOLUME, "volGroup2") +volGroup1.Add( volumes[init_nb_volumes/2:]) +MESH1.RemoveElements(rm_faces) +MESH1.MakeBoundaryMesh(volGroup1) +MESH1.MakeBoundaryMesh(volGroup2) +assert(init_nb_faces == MESH1.NbFaces()) +assert(init_nb_edges == MESH1.NbEdges()) + +# 1.1.4) to a submesh. +# The submesh has no volumes, so it is required to check if it passes without crash and does not create +# missing faces +faceSubmesh = MESH1.GetSubMesh( boxFace, "boxFace" ) +MESH1.RemoveElements(rm_faces) +MESH1.MakeBoundaryMesh(faceSubmesh) +assert(init_nb_faces != MESH1.NbFaces()) + +# check group creation +MESH1.RemoveElements(rm_faces) +groupName = "added to mesh" +m,group = MESH1.MakeBoundaryMesh(MESH1,groupName=groupName) +assert(group) +assert(group.GetName() == groupName) +assert(group.Size() == len(rm_faces)) + + +# 1.2) Create a new 3D Mesh MESH2 that consists of MESH1 and added 2D skin cells. +# ------------------------------------------------------------------------------ +MESH1.RemoveElements(rm_faces) +meshName = "MESH2" +MESH2,group = MESH1.MakeBoundaryMesh(MESH1,meshName=meshName,toCopyElements=True) +assert(MESH2) +assert(MESH2.GetName() == meshName) +assert(MESH2.NbVolumes() == MESH1.NbVolumes()) +assert(MESH2.NbFaces() == len(rm_faces)) + +# check group creation +MESH1.RemoveElements(rm_faces) +MESH2,group = MESH1.MakeBoundaryMesh(MESH1,meshName="MESH2_0", + groupName=groupName,toCopyElements=True) +assert(group) +assert(group.GetName() == groupName) +assert(group.Size() == len(rm_faces)) +assert(group.GetMesh()._is_equivalent(MESH2.GetMesh())) + +# 1.3) Create a new 2D Mesh MESH3 that consists only of 2D skin cells. +# ----------------------------------------------------------------------- +MESH1.RemoveElements(rm_faces) +meshName = "MESH3" +MESH3,group = MESH1.MakeBoundaryMesh(MESH1,meshName=meshName,toCopyExistingBondary=True) +assert(MESH3) +assert(not group) +assert(MESH3.GetName() == meshName) +assert(MESH3.NbVolumes() == 0) +assert(MESH3.NbFaces() == init_nb_faces) + +# check group creation +MESH1.RemoveElements(rm_faces) +MESH3,group = MESH1.MakeBoundaryMesh(MESH1,meshName=meshName, + groupName=groupName, toCopyExistingBondary=True) +assert(group) +assert(group.GetName() == groupName) +assert(group.Size() == len(rm_faces)) +assert(group.GetMesh()._is_equivalent(MESH3.GetMesh())) +assert(MESH3.NbFaces() == init_nb_faces) + +# ================================================================== +# 2) The mesh MESH1 with 3D cells has all its skin (2D cells) +# Create a new 2D Mesh MESH3 that consists only of 2D skin cells. +# ================================================================== +MESH1.MakeBoundaryMesh(MESH1) +MESH3,group = MESH1.MakeBoundaryMesh(MESH1,meshName=meshName,toCopyExistingBondary=True) +assert(MESH3) +assert(not group) +assert(MESH3.NbVolumes() == 0) +assert(MESH3.NbFaces() == init_nb_faces) + +# check group creation +MESH3,group = MESH1.MakeBoundaryMesh(MESH1,meshName=meshName, + groupName=groupName, toCopyExistingBondary=True) +assert(group) +assert(group.GetName() == groupName) +assert(group.Size() == 0) +assert(group.GetMesh()._is_equivalent(MESH3.GetMesh())) +assert(MESH3.NbFaces() == init_nb_faces) + +# ================ +# Make 1D from 2D +# ================ + +MESH1.Clear() +MESH1.Compute() +MESH1.RemoveElements( MESH1.GetElementsByType(SMESH.EDGE)) + +rm_faces = faceSubmesh.GetIDs()[:2] # to remove few adjacent faces +nb_missing_edges = 2 + 2*len(rm_faces) + +MESH1.RemoveElements(rm_faces) +mesh,group = MESH1.MakeBoundaryMesh(MESH1, BND_1DFROM2D) +assert( MESH1.NbEdges() == nb_missing_edges ) + + +\endcode */ diff --git a/doc/salome/gui/SMESH/input/use_existing_algos.doc b/doc/salome/gui/SMESH/input/use_existing_algos.doc new file mode 100644 index 000000000..b2273a4f0 --- /dev/null +++ b/doc/salome/gui/SMESH/input/use_existing_algos.doc @@ -0,0 +1,58 @@ +/*! + +\page import_algos_page Use Existing Elements Algorithms + +\n Use Existing Elements algorithms allow to define the mesh of a geometrical +object by the importing suitably located mesh elements from another +mesh. The mesh elements to import from the other mesh are to be contained in +groups. If several groups are used to mesh one geometry, validity of +nodal connectivity of result mesh must be assured by connectivity of +the source mesh; no geometrical checks are performed to merge +different nodes at same locations. +
              The source elements must totally cover the meshed geometry. +The source elements lying partially over the geometry will not be used. +
              +These algorithms can be used to mesh a very complex geometry part by +part, by storing meshes of parts in files and then fusing them +together using these algorithms. +
              + +Use Existing 1D Elements algorithm allows to define the mesh of +a geometrical edge (or group of edges) +by the importing of mesh edges of another mesh contained in a group (or groups). +\n To apply this algorithm select the edge to be meshed (indicated in +the field \b Geometry of Create mesh dialog box), +Use existing 1D elements in the list of 1D algorithms and click the +"Add Hypothesis" button. +The following dialog box will appear: + +\image html hyp_source_edges.png + +In this menu you can define the \b Name of the algorithm, the +Groups of Edges to import elements from, To copy mesh +the selected Groups of Edges belong to as a whole and To +copy groups along with the whole mesh. +
              + +Use Existing 2D Elements algorithm allows to define the mesh of +a geometrical face (or group of faces) +by the importing of mesh faces of another mesh contained in a group (or groups). +\n To apply this algorithm select the edge 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 +"Add Hypothesis" button. +The following dialog box will appear: + +\image html hyp_source_faces.png + +In this menu you can define the \b Name of the algorithm, the +Groups of Faces to import elements from, To copy mesh +the selected Groups of Fcaes belong to as a whole and To +copy groups along with the whole mesh. +
              + +
              See Also a sample TUI Script of a +\ref tui_import "Use Existing Elements Algorithms". + +*/ + diff --git a/doc/salome/gui/SMESH/input/volume.doc b/doc/salome/gui/SMESH/input/volume.doc index ba99c193e..4d74fcbf0 100644 --- a/doc/salome/gui/SMESH/input/volume.doc +++ b/doc/salome/gui/SMESH/input/volume.doc @@ -9,8 +9,8 @@
              1. Display your mesh in the viewer.
              2. -
              3. Choose Controls > Volume or click "Volume" button -in the toolbar. +
              4. Choose Controls > Volume Controls > Volume or click +"Volume" button in the toolbar. \image html image145.png
                "Volume" button
                diff --git a/doc/salome/gui/SMESH/input/warping.doc b/doc/salome/gui/SMESH/input/warping.doc index 83bfaa3ac..86ba0c905 100644 --- a/doc/salome/gui/SMESH/input/warping.doc +++ b/doc/salome/gui/SMESH/input/warping.doc @@ -24,8 +24,8 @@ projection height ?h? to the half edge length ?l?.
                1. Display your mesh in the viewer.
                2. -
                3. Choose Controls > Warping Angle or click "Warping angle" -button of the toolbar. +
                4. Choose Controls > Face Controls > Warping Angle or click +"Warping angle" button of the toolbar. \image html image39.png
                  "Warping angle" button
                  diff --git a/idl/Makefile.am b/idl/Makefile.am index 5a88808b3..491c38667 100644 --- a/idl/Makefile.am +++ b/idl/Makefile.am @@ -32,7 +32,8 @@ BASEIDL_FILES = \ SMESH_Filter.idl \ SMESH_Group.idl \ SMESH_Pattern.idl \ - SMESH_MeshEditor.idl + SMESH_MeshEditor.idl \ + SMESH_Measurements.idl # This variable defines the files to be installed dist_salomeidl_DATA = $(BASEIDL_FILES) @@ -49,7 +50,8 @@ nodist_libSalomeIDLSMESH_la_SOURCES = \ SMESH_FilterSK.cc \ SMESH_GroupSK.cc \ SMESH_PatternSK.cc \ - SMESH_MeshEditorSK.cc + SMESH_MeshEditorSK.cc \ + SMESH_MeasurementsSK.cc # header files must be exported: other modules have to use this library nodist_salomeinclude_HEADERS = $(BASEIDL_FILES:%.idl=%.hh) diff --git a/idl/SMESH_BasicHypothesis.idl b/idl/SMESH_BasicHypothesis.idl index 871f07714..88b0ab751 100644 --- a/idl/SMESH_BasicHypothesis.idl +++ b/idl/SMESH_BasicHypothesis.idl @@ -753,6 +753,16 @@ module StdMeshers /*! * StdMeshers_QuadrangleParams: interface of "Quadrangle Params" hypothesis */ + enum QuadType + { + QUAD_STANDARD, + QUAD_TRIANGLE_PREF, + QUAD_QUADRANGLE_PREF, + QUAD_QUADRANGLE_PREF_REVERSED, + QUAD_REDUCED, + QUAD_NB_TYPES /* this is not a type of quadrangulation */ + }; + interface StdMeshers_QuadrangleParams : SMESH::SMESH_Hypothesis { /*! @@ -774,6 +784,58 @@ module StdMeshers * Get the entry of the main object */ string GetObjectEntry(); + + /*! + * Set the type of quadrangulation + */ + void SetQuadType( in QuadType type ); + + /*! + * Get the type of quadrangulation + */ + QuadType GetQuadType(); + }; + + /*! + * interface of "Source edges" hypothesis. + * This hypothesis specifies groups of edges of other mesh to be imported + * in this mesh + */ + interface StdMeshers_ImportSource1D : SMESH::SMESH_Hypothesis + { + /*! + * Set edges to import from other mesh + */ + void SetSourceEdges(in SMESH::ListOfGroups groups); + SMESH::string_array GetSourceEdges(); + + /*! + * Set to import the whole other mesh or not, and if yes, to + * copy groups of not. By default the mesh is not copied. + */ + void SetCopySourceMesh(in boolean toCopyMesh, in boolean toCopyGroups); + void GetCopySourceMesh(out boolean toCopyMesh,out boolean toCopyGroups); + }; + + /*! + * interface of "Source faces" hypothesis. + * This hypothesis specifies groups of faces of other mesh to be imported + * in this mesh + */ + interface StdMeshers_ImportSource2D : SMESH::SMESH_Hypothesis + { + /*! + * Set faces to import from other mesh + */ + void SetSourceFaces(in SMESH::ListOfGroups groups); + SMESH::string_array GetSourceFaces(); + + /*! + * Set to import the whole other mesh or not, and if yes, to + * copy groups of not. By default the mesh is not copied. + */ + void SetCopySourceMesh(in boolean toCopyMesh,in boolean toCopyGroups); + void GetCopySourceMesh(out boolean toCopyMesh,out boolean toCopyGroups); }; /*! @@ -876,6 +938,19 @@ module StdMeshers { }; + /*! + * StdMeshers_Import_1D2D: interface of "Use existing 2D elements" algorithm + */ + interface StdMeshers_Import_1D2D : SMESH::SMESH_2D_Algo + { + }; + /*! + * StdMeshers_Import_1D: interface of "Use existing 1D elements" algorithm + */ + interface StdMeshers_Import_1D : SMESH::SMESH_1D_Algo + { + }; + }; #endif diff --git a/idl/SMESH_Filter.idl b/idl/SMESH_Filter.idl index 56f2cdce2..e12607bcd 100644 --- a/idl/SMESH_Filter.idl +++ b/idl/SMESH_Filter.idl @@ -47,6 +47,8 @@ module SMESH FT_Skew, FT_Area, FT_Volume3D, + FT_MaxElementLength2D, + FT_MaxElementLength3D, FT_FreeBorders, FT_FreeEdges, FT_FreeNodes, @@ -65,6 +67,7 @@ module SMESH FT_LinearOrQuadratic, FT_GroupColor, FT_ElemGeomType, + FT_CoplanarFaces, FT_LessThan, FT_MoreThan, FT_EqualTo, @@ -74,6 +77,17 @@ module SMESH FT_Undefined }; + /*! + * Parameters of a reclangle of histogram + */ + struct HistogramRectangle + { + long nbEvents; + double min; + double max; + }; + typedef sequence Histogram; + /*! * Base interface for all functors ( i.e. numerical functors and predicates ) */ @@ -93,6 +107,8 @@ module SMESH { double GetValue( in long theElementId ); + Histogram GetHistogram( in short nbIntervals ); + /*! * Set precision for calculation. It is a position after point which is * used to functor value after calculation. @@ -108,6 +124,8 @@ module SMESH interface Skew : NumericalFunctor{}; interface Area : NumericalFunctor{}; interface Volume3D : NumericalFunctor{}; + interface MaxElementLength2D : NumericalFunctor{}; + interface MaxElementLength3D : NumericalFunctor{}; interface Length : NumericalFunctor{}; interface Length2D : NumericalFunctor { @@ -346,6 +364,16 @@ module SMESH void SetGeometryType( in GeometryType theType ); }; + /*! + * Functor "Coplanar faces" + * Returns true if a mesh face is a coplanar neighbour to a given one. It checks + * if normal of a face has angle with the threshold face less than a tolerance. + */ + interface CoplanarFaces : Predicate{ + void SetFace ( in long theFaceID ); + void SetTolerance( in double theToler ); + }; + /*! * Filter */ @@ -360,13 +388,13 @@ module SMESH * BinaryOp - binary logical operation FT_LogicalAND, FT_LogicalOR or * (FT_Undefined must be for the last criterion) * ThresholdStr - Threshold value defined as string. Used for: - * 1. Diaposon of identifiers. Example: "1,2,3,5-10,12,27-29" + * 1. Diapason of identifiers. Example: "1,2,3,5-10,12,27-29" * 2. BelongToGeom predicate for storing name of shape * 3. GroupColor predicate for storing group color "0.2;0;0.5" * ThresholdID - One more threshold value defined as string. Used for: * 1. BelongToGeom predicate for storing id of shape * Tolerance - Tolerance is used for comparators (EqualTo comparision) and for - * "Belong to plane" and "Belong to cylinder" predicates + * "Belong to plane", "Belong to cylinder" etc predicates * TypeOfElement - type of element SMESH::NODE, SMESH::FACE (used by BelongToGeom predicate only) * Precision - Precision of numerical functors */ @@ -450,6 +478,8 @@ module SMESH Skew CreateSkew(); Area CreateArea(); Volume3D CreateVolume3D(); + MaxElementLength2D CreateMaxElementLength2D(); + MaxElementLength3D CreateMaxElementLength3D(); Length CreateLength(); Length2D CreateLength2D(); MultiConnection CreateMultiConnection(); @@ -477,6 +507,7 @@ module SMESH GroupColor CreateGroupColor(); ElemGeomType CreateElemGeomType(); + CoplanarFaces CreateCoplanarFaces(); /*! * Create comparators ( predicates ) diff --git a/idl/SMESH_Gen.idl b/idl/SMESH_Gen.idl index 14527a9b3..3c375e625 100644 --- a/idl/SMESH_Gen.idl +++ b/idl/SMESH_Gen.idl @@ -42,6 +42,7 @@ module SMESH interface FilterManager; interface SMESH_Pattern; + interface Measurements; /*! * Tags definition @@ -119,6 +120,8 @@ module SMESH SMESH_Pattern GetPattern(); + Measurements CreateMeasurements(); + /*! Set the current mode */ @@ -244,7 +247,6 @@ module SMESH */ long_array Evaluate(in SMESH_Mesh theMesh, in GEOM::GEOM_Object theSubObject) - //inout long_array theNbElems) raises ( SALOME::SALOME_Exception ); /*! diff --git a/idl/SMESH_Group.idl b/idl/SMESH_Group.idl index c0bb54bc9..adf63dd83 100644 --- a/idl/SMESH_Group.idl +++ b/idl/SMESH_Group.idl @@ -82,11 +82,6 @@ module SMESH */ long_array GetListOfID(); - /*! - * Returns the mesh object this group belongs to - */ - SMESH_Mesh GetMesh(); - /*! * Sets group color */ @@ -121,15 +116,25 @@ module SMESH void Clear(); /*! - * Adds elements to the group + * Adds elements or nodes with specified identifiers to the group */ long Add( in long_array elem_ids ); + /*! + * Adds elements or nodes that match specified predicate to the group + */ long AddByPredicate( in Predicate thePredicate ); + /*! + * Add all elements or nodes from the specified source to the group + */ + long AddFrom( in SMESH_IDSource theSource ); /*! - * Removes elements from the group + * Removes elements or nodes with specified identifiers from the group */ long Remove( in long_array elem_ids ); + /*! + * Removes elements or nodes that match specified predicate from the group + */ long RemoveByPredicate( in Predicate thePredicate ); }; diff --git a/idl/SMESH_Measurements.idl b/idl/SMESH_Measurements.idl new file mode 100644 index 000000000..6a177f51a --- /dev/null +++ b/idl/SMESH_Measurements.idl @@ -0,0 +1,61 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// File : SMESH_Measurements.idl +// Author : Pavel Telkov, OCC +// +#ifndef _SMESH_MEASUREMENTS_IDL_ +#define _SMESH_MEASUREMENTS_IDL_ + +#include "SALOME_GenericObj.idl" +#include "SMESH_Mesh.idl" + +module SMESH +{ + + /* + * Measure component + */ + struct Measure { + double minX, minY, minZ; + double maxX, maxY, maxZ; + long node1, node2; + long elem1, elem2; + double value; + }; + + interface Measurements: SALOME::GenericObj + { + /*! + * minimal distance between two entities + */ + Measure MinDistance(in SMESH_IDSource source1, + in SMESH_IDSource source2); + + /*! + * common bounding box of entities + */ + Measure BoundingBox(in ListOfIDSources sources); + }; +}; + +#endif diff --git a/idl/SMESH_Mesh.idl b/idl/SMESH_Mesh.idl index a06e663d5..8165d5c00 100644 --- a/idl/SMESH_Mesh.idl +++ b/idl/SMESH_Mesh.idl @@ -37,6 +37,8 @@ module SMESH typedef sequence ListOfHypothesis; interface SMESH_GroupBase; typedef sequence ListOfGroups; + interface SMESH_IDSource; + typedef sequence ListOfIDSources; typedef sequence double_array ; typedef sequence long_array ; @@ -116,6 +118,7 @@ module SMESH VOLUME, ELEM0D }; + typedef sequence array_of_ElementType ; /*! * Enumeration for element geometry type, like in SMDS @@ -245,6 +248,8 @@ module SMESH long_array elementConnectivities; types_array elementTypes; }; + interface SMESH_Mesh; + interface SMESH_IDSource { /*! @@ -257,6 +262,16 @@ module SMESH * Result array of number enityties */ long_array GetMeshInfo(); + + /*! + * Returns types of elements it contains + */ + array_of_ElementType GetTypes(); + + /*! + * Returns the mesh + */ + SMESH_Mesh GetMesh(); }; interface SMESH_Group; diff --git a/idl/SMESH_MeshEditor.idl b/idl/SMESH_MeshEditor.idl index 983b2f486..c010980be 100644 --- a/idl/SMESH_MeshEditor.idl +++ b/idl/SMESH_MeshEditor.idl @@ -29,6 +29,8 @@ module SMESH { + enum Bnd_Dimension { BND_2DFROM3D, BND_1DFROM3D, BND_1DFROM2D }; + /*! * This interface makes modifications on the Mesh - removing elements and nodes etc. */ @@ -37,13 +39,38 @@ module SMESH { /*! * \brief Wrap a sequence of ids in a SMESH_IDSource + * \param IDsOfElements list of mesh elements identifiers + * \return new ID source object */ - SMESH_IDSource MakeIDSource(in long_array IDsOfElements); + SMESH_IDSource MakeIDSource(in long_array IDsOfElements, in ElementType type); + /*! + * \brief Remove mesh elements specified by their identifiers. + * \param IDsOfElements list of mesh elements identifiers + * \return \c true if elements are correctly removed or \c false otherwise + */ boolean RemoveElements(in long_array IDsOfElements); + /*! + * \brief Remove mesh nodes specified by their identifiers. + * \param IDsOfNodes list of mesh nodes identifiers + * \return \c true if nodes are correctly removed or \c false otherwise + */ boolean RemoveNodes(in long_array IDsOfNodes); + + /*! + * \brief Remove all orphan nodes. + * \return number of removed nodes + */ + long RemoveOrphanNodes(); + /*! + * \brief Add new node. + * \param x X coordinate of new node + * \param y Y coordinate of new node + * \param z Z coordinate of new node + * \return integer identifier of new node + */ long AddNode(in double x, in double y, in double z); /*! @@ -222,6 +249,7 @@ module SMESH * \param methodFlags - flags passing splitting method: * 1 - split the hexahedron into 5 tetrahedrons * 2 - split the hexahedron into 6 tetrahedrons + * 3 - split the hexahedron into 24 tetrahedrons */ void SplitVolumesIntoTetra(in SMESH_IDSource elems, in short methodFlags) raises (SALOME::SALOME_Exception); @@ -616,6 +644,11 @@ module SMESH in double Tolerance, out array_of_long_array GroupsOfNodes); + void FindCoincidentNodesOnPartBut (in SMESH_IDSource SubMeshOrGroup, + in double Tolerance, + out array_of_long_array GroupsOfNodes, + in ListOfIDSources ExceptSubMeshOrGroups); + void MergeNodes (in array_of_long_array GroupsOfNodes); /*! @@ -759,11 +792,23 @@ module SMESH * \param theNodes - group of nodes to be doubled. * \param theModifiedElems - group of elements to be updated. * \return TRUE if operation has been completed successfully, FALSE otherwise - * \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups() + * \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups(), DoubleNodeGroupNew() */ boolean DoubleNodeGroup( in SMESH_GroupBase theNodes, in SMESH_GroupBase theModifiedElems ); + /*! + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements. + * Works as DoubleNodeGroup() described above, but returns a new group with + * newly created nodes. + * \param theNodes - group of nodes to be doubled. + * \param theModifiedElems - group of elements to be updated. + * \return a new group with newly created nodes + * \sa DoubleNodeGroup() + */ + SMESH_Group DoubleNodeGroupNew( in SMESH_GroupBase theNodes, + in SMESH_GroupBase theModifiedElems ); + /*! \brief Creates a hole in a mesh by doubling the nodes of some particular elements This method provided for convenience works as DoubleNodes() described above. @@ -812,12 +857,27 @@ module SMESH * \param theAffectedElems - group of elements to which the replicated nodes * should be associated to. * \return TRUE if operation has been completed successfully, FALSE otherwise - * \sa DoubleNodes(), DoubleNodeGroups() + * \sa DoubleNodes(), DoubleNodeGroups(), DoubleNodeElemGroupNew() */ boolean DoubleNodeElemGroup( in SMESH_GroupBase theElems, in SMESH_GroupBase theNodesNot, in SMESH_GroupBase theAffectedElems ); + /*! + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements. + * Works as DoubleNodeElemGroup() described above, but returns a new group with + * newly created elements. + * \param theElems - group of of elements (edges or faces) to be replicated + * \param theNodesNot - group of nodes not to replicated + * \param theAffectedElems - group of elements to which the replicated nodes + * should be associated to. + * \return a new group with newly created elements + * \sa DoubleNodeElemGroup() + */ + SMESH_Group DoubleNodeElemGroupNew( in SMESH_GroupBase theElems, + in SMESH_GroupBase theNodesNot, + in SMESH_GroupBase theAffectedElems ); + /*! * \brief Creates a hole in a mesh by doubling the nodes of some particular elements * This method provided for convenience works as DoubleNodes() described above. @@ -863,12 +923,34 @@ module SMESH in GEOM::GEOM_Object theShape ); /*! - * \brief Generated skin mesh (containing 2D cells) from 3D mesh + * \brief Generates skin mesh (containing 2D cells) from 3D mesh * The created 2D mesh elements based on nodes of free faces of boundary volumes * \return TRUE if operation has been completed successfully, FALSE otherwise */ boolean Make2DMeshFrom3D(); + /*! + * \brief Creates missing boundary elements + * \param elements - elements whose boundary is to be checked + * \param dimension - defines type of boundary elements to create + * \param groupName - a name of group to store created boundary elements in, + * "" means not to create the group + * \param meshName - a name of new mesh to store created boundary elements in, + * "" means not to create the new mesh + * \param toCopyElements - if true, the checked elements will be copied into the new mesh + * \param toCopyExistingBondary - if true, not only new but also pre-existing + * boundary elements will be copied into the new mesh + * \param group - returns the create group, if any + * \retval SMESH::SMESH_Mesh - the mesh where elements were added to + */ + SMESH::SMESH_Mesh MakeBoundaryMesh(in SMESH_IDSource elements, + in Bnd_Dimension dimension, + in string groupName, + in string meshName, + in boolean toCopyElements, + in boolean toCopyExistingBondary, + out SMESH_Group group); + }; }; diff --git a/resources/Makefile.am b/resources/Makefile.am index 97f2c3b6f..cc7d5a885 100644 --- a/resources/Makefile.am +++ b/resources/Makefile.am @@ -49,6 +49,7 @@ dist_salomeres_DATA = \ mesh_info.png \ advanced_mesh_info.png \ standard_mesh_info.png \ + mesh_elem_info.png \ mesh_whatis.png \ mesh_init.png \ mesh_length.png \ @@ -57,6 +58,8 @@ dist_salomeres_DATA = \ mesh_free_edges.png \ mesh_free_edges_2d.png \ mesh_free_nodes.png \ + mesh_max_element_length_2d.png \ + mesh_max_element_length_3d.png \ mesh_multi_edges.png \ mesh_multi_edges_2d.png \ mesh_line_n.png \ @@ -70,8 +73,14 @@ dist_salomeres_DATA = \ mesh_pyramid.png \ mesh_quad_n.png \ mesh_quad.png \ + mesh_quadrangle_quadpref.png \ + mesh_quadrangle_quadpref_reversed.png \ + mesh_quadrangle_reduced.png \ + mesh_quadrangle_standard.png \ + mesh_quadrangle_triapref.png \ mesh_rem_element.png \ mesh_rem_node.png \ + mesh_rem_orphan_nodes.png \ mesh_shading.png \ mesh_shrink.png \ mesh_skew.png \ @@ -172,7 +181,11 @@ dist_salomeres_DATA = \ mesh_free_faces.png \ scale.png \ scale_along_axes.png \ - split_into_tetra.png + split_into_tetra.png \ + mesh_duplicate_nodes.png \ + mesh_duplicate_nodes_with_elem.png \ + mesh_bounding_box.png \ + mesh_min_dist.png # VSR: little trick to avoid putting if SMESHCatalog.xml to the distribution archive nodist_salomeres_SCRIPTS = SMESHCatalog.xml diff --git a/resources/SalomeApp.xml b/resources/SalomeApp.xml index e4ddfa738..ea6daa0bf 100644 --- a/resources/SalomeApp.xml +++ b/resources/SalomeApp.xml @@ -33,6 +33,7 @@ + @@ -64,11 +65,16 @@ + + + + + diff --git a/resources/StdMeshers.xml b/resources/StdMeshers.xml index d267ef1f6..41c83c997 100644 --- a/resources/StdMeshers.xml +++ b/resources/StdMeshers.xml @@ -40,7 +40,7 @@ dim="0"/> @@ -122,7 +122,6 @@ + + + + + + + + r16)Z&K~y-)t(0A8TV)u>f9G_qG+ncmnq{3AQrCi$ff<`#bWX}z zos-Ebi)$||yKoy`)UH7(aa0kUqOBL&MzJ6$1wke_YS_At`mw=u6Dn=8Q9oK`R+F@3 z%~{V$&PQ_2>&0?PyG?Pj2Y()TpXcKDJ|FxaNeIE6G?_bWtK5eqNdRjuLyw&{NJ2(!gswzy=WNd6q`cFX1vS@05jei$(JvlHiPy?VS z3c4kbfTxapR0Ow(TrNjE9+&=g%bKQP<{cVZUnLj}CV}Z_G`jnPmmVi;+US;po_E+2 z8sgz#4?f@B!sGD>zu#YbOW^ft9CD_^&O-wP0)Zruip65#zQfzNrsbLWDbAH2`f0v@ zl+zgJ_0L)+nIoG~PS3 z3E0)YVmTq2-hi0!^7iz4{j)hnoPt z1vG%gt4T^qD}V4*ZQ!1&IfhTv)fue{n*rO{VOUMO9>0oWUDf4gmX#?T!{N z&#vMJ)4+LPqPn`eKA+FG+O~b4ZQJ99VSET&yA`mm2u&3|0QiBKA~5A{{h#b_!jiRi UrkA3>01E&B07*qoM6N<$f=q+RS^xk5 delta 933 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 b%C`XkOU=6O=JF+100000NkvXXu0mjfKW>gN literal 0 HcmV?d00001 diff --git a/resources/mesh_duplicate_nodes.png b/resources/mesh_duplicate_nodes.png new file mode 100644 index 0000000000000000000000000000000000000000..0f800f7a249893c0db7b4a2c6fd8075bf058f647 GIT binary patch literal 914 zcmV;D18w|?P)TvZr`pCdzNG8$Z(of`)iifL&qh)RQKtDP8WMX7CV(e#I4NFix0@wbY# zsc3&RYHL+AB_^fXB3hvfDOwsKwNixcgi^ZDT{5{pXU@+(pNmXF#*8kcFC4ymF7Ns7 z_n!MG5#dJaCT_4)xm=c}rY4k9WLbtW2CX$(YmR?0$@2SdRSOSH{!)>F7duf(;he)5 zLli~Cam@7eH0qVXFzM zqoYISjA@z@$1zh=Q)sRE?PAg}@`g?AhzMG1q9~$Lso=c_AlEf8%89quvUczrj1z`m zSjNWv7qB{EY5N0gIXF=_;p)e`cy9k`1US}zKkN6MN9&YNceJza_3z2~Z1zjm3&sbM zB*CN+&LlKK%36!hgdmWnDb_k%HAO^lR-@Y5+Qd1B)|#1_8LHJPB7%r;`I2rJdF5lb z9;N%e^JGC7 z?pZ?jp^H@G3ddi1h$nZS_&2bnwi=8M`Js zN3Ke-Sd?uCC*=8e&PhI>mqMW+eMhg*ck~K{LP1KUlDv8Hy1Y7mOWZnU=?eHZ&*|ALKp1*$M5sVKwFN6@VI>FV>W!|D% zTU#YfQ?e|p9~}rGP$(1@-BSpG5JH`QuBx3QSLNfLyLoosIjoKu+f(L=fe{e+_P{2# z9{RPe*=POB={_)tH3?ttUcs7OU*Sy3cZa(v_Z}f%8-EYe+2tHrHw+{Q;b1BCpEP)lFf72fJoISO4+1^Aq9fCDjNfV@tmLet2VrdYj=2Dx6w5+geN&hV} zw+K_($W?<{vDLIBDx-@KlQvj0BJeH{@us`|^L^jUnLppWUF_LqPkXkD@PXl-8J_o@ z_j%`0BErqYE!QUOXmvK|8NwA;>_@7 zdInEY^TNmd_p^0)fjmp0Ns{1d8LGRxTL8TG zXst=pl&PsHj4}LvIcq9;>-N=%2*wzaBw=P|h7bY(g$+X|IsMKiHog26)(ayqtYX`H zzu-(pOXqz}B|m=l90D90e1I(nE@6!3`0mwge)BsDA)kB61;K_$mStF-;BB_7V29$(Xl2;Lb~S67#K?=i+OJ3C9QRzpM(5&pPhno3^x=v{;mNYj)M!U7+l@YKHV z8GCgdy~7tVJ~HzB3byV432!wmoewva{LGh^$fGc_YbAY$E>lZqIPuCuJhAuma>kbW zTE@KpW$gbWdBetg77V?Z55T)$-;heBBCm~Kmpxt3EdZ~yMDg}{{R$N3}3U! ReUShF002ovPDHLkV1f*boofI9 literal 0 HcmV?d00001 diff --git a/resources/mesh_elem_info.png b/resources/mesh_elem_info.png new file mode 100644 index 0000000000000000000000000000000000000000..9937d6d88586b9f0b8f62db1f680167ffcf779bd GIT binary patch literal 907 zcmV;619bd}P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igi8 z69p{^#?W>E00Rq2L_t(I%dM16Xk1kk$A5R`<$DaRDQ|)rD|QwJDo#74?T{3!bTP?` zn~uQW-qG>>_~>X`Jb*p`Gz`P6t*z}?SQsS| ziJbI2?^dZ)Dpr1C{Hvx;kSzgdF4!X)jfTQumDu}o%UhPU^|jX4dAXO}*E^h^y_+8S zv;W4=e|-bkJfyK3fHupzEWnn^W;7a&9ysvg#reB^;ujB!@AZi9b%~SPEg!u9teB>` zeYM7R06P>i2xbS{yQ`}&aeaD>ufD!aHamk~`h$J1YU=Ab*4WrswVG1w zp`k>3clYFY07b<2zdOJ1_lKvJIex;)9y*-8Id(qJ?b}6W=ZaKS$&yI|ORnp}Bg~-zXzT8ttkhDa zQWpg1d}Z&`mwx+Ym;5^SjJ)^mCW*(JmTPKi4g>X%G6x5+wHAP8%bF->GJ9f%VQgw? zsf&sf`RRt{+&Qu{GfuzfdEWw_v4%A5vuC%rTh_$5)*e8!*4n#zHD5S!(j}WMGdriR z=kxBTz$~EGvM&d)MKqbro<1OE7{*dE8B!me4s-mN;Ijm`$!Q2OAnwpxPDwRraXsw^uTL0*}?kB*##{s?s h^aOex2z39@xDUtgVtTen16BY4002ovPDHLkV1klprFZ}U literal 0 HcmV?d00001 diff --git a/resources/mesh_max_element_length_2d.png b/resources/mesh_max_element_length_2d.png new file mode 100755 index 0000000000000000000000000000000000000000..d0120fa1ede5f2785da08336bfa85689607c8d9d GIT binary patch literal 857 zcmV-f1E&0mP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;&q+i>;4wDVIRNfJ{J{9CArAN&bQyOcrGSfFQDgb#hQa*=6x!u9?Xpr*tB5 zoSvR;+pekFgWa0!dJ%HSgD+Kw$LIavy(f$@d`pvjWBdMrVqsyySeAulS(M9VaaO?m z{JaT*fP;ermX?-;9Yql-n(7KSFi|09cwi_FZ- z0A%eT2pAh1!}C0KuVAjgg6m^F`zZH+t6+s;ut*dCR0;WL{S7VE`Te*P2kE0 z(_5%+zE6PSD<~Ynj(~S9SYBSHbgPGKHe0AxtM`B%phm0JVqjpv z%+1Xi*L49p9mg@iqii;79LM=e&!7Ke9LF)Uv$FFDTS zcX!v^cypL%UhgQl2iHYNCPQ5l~JTAv;ngsYg4RqYY jGXlRHliGjF1^9OWjdNV6x1YOp00000NkvXXu0mjfRrhtP literal 0 HcmV?d00001 diff --git a/resources/mesh_max_element_length_3d.png b/resources/mesh_max_element_length_3d.png new file mode 100755 index 0000000000000000000000000000000000000000..7b6b895a1d83a5d1393a3af60c2a8fbe4a7c0433 GIT binary patch literal 965 zcmV;$13LVPP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZq>)?Vof(C zC13~yM`(&}M6`?8O1r2b5?W%XNEbp2VxZt!QX&$v4B03F#ejC@!laF5bcQ5;kQp+R z(#*Vj-+OcKJucqIq$PIcfy@7LIsDJp|6ET*_&+TN;CbF-kF&G0S(LfCIqzu%larIu zYPIlvpVie>FL#(zS63JLe4cu}&I5TzzyShu0U#J4L{NP6uBNxQmqw!jFp&GN$h*6{ z7-RVJ*QJ<5!1H1h0c+#4zkh~Wt%flM;7w0N9xM5QyeI$M{RZd2xeh^UBJsPm!iysV z{PshcBgc>OTHnJpU_A#gH8myO-Q9Se$KM-YWMl^kQ_@?v&Ju{>!VhyadhZ((jScwB>l2U524i>pin4KsZ>y^iPnlh15gJxasW{jv9q&- zbB^s_zRgNHtYoF$pi-$|ttAXKQ50a>oeaAGs?{o=&zHG$=_{OrD_6#{UX@B?T)P$@ zYlZ9Azr#7l`1m-+v~kYz@!97)3IQ<2aQb9~2ux3pptVkjM;IL)<>t*bZru2hnVFM_ zIFwR^VTf}U=WIIRj# zn0~*Pp`oFfEW_BbjdPO7#SsKL>(#`>XNWj1Uw$2>nwh^+O{}$~96%uxc3obPKYqH0 zF%GR;Xzde4ai2WT!#Rhw24f=nj*U~kvqThyEG~YUt?TCIW+_`eLDOzqe19LMngl^i zDB_Y0k&LjpFKF#^R=lwkGA!2b>aM@J*Ey`lN)00000NkvXXu0mjfoe{Pk literal 0 HcmV?d00001 diff --git a/resources/mesh_min_dist.png b/resources/mesh_min_dist.png new file mode 100755 index 0000000000000000000000000000000000000000..6713caf0ae83217fe99fb810ec5d3778cbe84470 GIT binary patch literal 3360 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 literal 0 HcmV?d00001 diff --git a/resources/mesh_quadrangle_reduced.png b/resources/mesh_quadrangle_reduced.png new file mode 100644 index 0000000000000000000000000000000000000000..985c23647aae21a59b8118492a770800387ca4e3 GIT binary patch literal 459 zcmV;+0W|)JP)V7a8bs0s0Ixk$r}cAU~2u z3tUIcOhi3sJ$>jv?+55I5@P1Ajz8u?0wafz1P*_Q6C<;N%9S^e*Ds=bYmD=4lhf$_ zq2v8B$TLoXA6FW@tq9z4nF@!e%D^u&E4u75OQ*&%@QaLDm%V1`R9FW6ml<>aWx*`^pIEQVh}_El z=aF;{$j%{4m+$NYrAZ1qQ}jFvnL|<)7cuDKT+dEvGGg9Px_?=ohTkdHq2v1u_j9<< z@9L|^fZ^+_qW>}@PUC8NTi!8f*OBs`RF=j;MwO{PAJyzW{Ba_6*pGP#%FgTFBWSF4b$)RQ7cy-_5cC;lnE3@=L_Q8dNB(}hYOVkP002ovPDHLkV1iaw B(VhSR literal 0 HcmV?d00001 diff --git a/resources/mesh_quadrangle_standard.png b/resources/mesh_quadrangle_standard.png new file mode 100644 index 0000000000000000000000000000000000000000..957a0f20d7aeaee6d3c5f54e9f7b652d999fbf4f GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^u|RCd!2~4DRgJa+so$P1jv*P1Z)Z4i9X8-$nR_Yx z#sB=v)>Rxcg7Up`x}!{um(Q7&D)M^4;k(>h9xOe2cmCIGwG(Ha{Z->M+#GZ&dDHQA z4_uqYdE-nfE@CitHds4zm$S_csBjO*kVI1cl>armLi-9$GLx_PST<5${{`?G2XP_Woq) zel=o4{G=Iw=UsT7`g?28%MX+OKj-J!`TA-6GnvrG<-b)sZ|>%lWShZTZvR24lCk;e WmS8`p?E%1GVDNPHb6Mw<&;$TlwT0^d literal 0 HcmV?d00001 diff --git a/resources/mesh_quadrangle_triapref.png b/resources/mesh_quadrangle_triapref.png new file mode 100644 index 0000000000000000000000000000000000000000..d14440d95d348e36fa685d0ad43ce36264aa4391 GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^u|RCd!2~4DRgJbXFfjUgx;TbpG`^kb$alzqhlTl( z=+FPR|M2m7EHs&I(s{S(!WquSEt`(7<$soz#+mgYC^@bF(@Ehe#ovDaoj74mvDeFY zYaYiR>}J!K+LQ5N5eDN@gS9hnIosR`75z~UT${yt<4h_pVqq+0{62lw_rI!^EPMIH z=C$1C)a3jw6tXYs@Z^9#PesMkIl_B>r_SDb?dm%D`i}ZznXgk7*U1HX_-<~QvXT2| zMclGS=d6#nohbdbslI<*jEU@KMaAY5El2-eTA#LL_2Ifdit{A7_1g=Tm3JjvY?*SA z>*9HD^>?T0E6>H5%r%Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igY) z5*ZM2FW5%_000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0007lNklij?9ygXA$qJJ zFCCIv5Iu!?=^!lSVGzotc3aI+s&#kVSy$QF*P)qhTwRr*|K;O-@4X-Y_kHg@iGNUg zd%Nfzena2oGxWcB$LFu}XbFStMh>ZXaamcJ05DBcDh2Btc+JqQ^IRQ#%lCMc%!bKY zcAe$O46afxWH}&!3TLjZtxfnI{DE~@Fk?N3VPw!gg&FDhQCwN*TM=A-Mr<+S(a0Ha136Qxi`| zuXFaq5jqDaNhg1z&3$0>Q4h+EdxVC2x8+m-$7DGm6eTR0o12AG)z#JFoAF!#;^OVc z0uU`%?%1)UxkIuX5RHwEqFA|HP5@&3{apcw3%*`EZYE5--D2A97Pd=S4hXN;y9t)b zWJD|$6H`-D0uUpw?%T1zk(@w)Q;UmsuCA)8Dw;~A$mjFux=tdIAQp?Uva*7vY54tq zTrL+44Smec4gmaZiUVXT>-BacNfMDr1YOrjCX=L6sRB$ +#include #include #include @@ -70,6 +71,12 @@ */ namespace{ + + inline gp_XYZ gpXYZ(const SMDS_MeshNode* aNode ) + { + return gp_XYZ(aNode->X(), aNode->Y(), aNode->Z() ); + } + inline double getAngle( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 ) { gp_Vec v1( P1 - P2 ), v2( P3 - P2 ); @@ -171,6 +178,26 @@ namespace{ return aResult; } + gp_XYZ getNormale( const SMDS_MeshFace* theFace, bool* ok=0 ) + { + int aNbNode = theFace->NbNodes(); + + gp_XYZ q1 = gpXYZ( theFace->GetNode(1)) - gpXYZ( theFace->GetNode(0)); + gp_XYZ q2 = gpXYZ( theFace->GetNode(2)) - gpXYZ( theFace->GetNode(0)); + gp_XYZ n = q1 ^ q2; + if ( aNbNode > 3 ) { + gp_XYZ q3 = gpXYZ( theFace->GetNode(3)) - gpXYZ( theFace->GetNode(0)); + n += q2 ^ q3; + } + double len = n.Modulus(); + bool zeroLen = ( len <= numeric_limits::min()); + if ( !zeroLen ) + n /= len; + + if (ok) *ok = !zeroLen; + + return n; + } } @@ -178,8 +205,8 @@ namespace{ using namespace SMESH::Controls; /* - FUNCTORS -*/ + * FUNCTORS + */ /* Class : NumericalFunctor @@ -277,6 +304,63 @@ double NumericalFunctor::GetValue( long theId ) return 0.; } +//================================================================================ +/*! + * \brief Return histogram of functor values + * \param nbIntervals - number of intervals + * \param nbEvents - number of mesh elements having values within i-th interval + * \param funValues - boundaries of intervals + */ +//================================================================================ + +void NumericalFunctor::GetHistogram(int nbIntervals, + std::vector& nbEvents, + std::vector& funValues) +{ + if ( nbIntervals < 1 || + !myMesh || + !myMesh->GetMeshInfo().NbElements( GetType() )) + return; + nbEvents.resize( nbIntervals, 0 ); + funValues.resize( nbIntervals+1 ); + + // get all values sorted + std::multiset< double > values; + SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(GetType()); + while ( elemIt->more() ) + values.insert( GetValue( elemIt->next()->GetID() )); + + // case nbIntervals == 1 + funValues[0] = *values.begin(); + funValues[nbIntervals] = *values.rbegin(); + if ( nbIntervals == 1 ) + { + nbEvents[0] = values.size(); + return; + } + // case of 1 value + if (funValues.front() == funValues.back()) + { + nbEvents.resize( 1 ); + nbEvents[0] = values.size(); + funValues[1] = funValues.back(); + funValues.resize( 2 ); + } + // generic case + std::multiset< double >::iterator min = values.begin(), max; + for ( int i = 0; i < nbIntervals; ++i ) + { + double r = (i+1) / double( nbIntervals ); + funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r; + if ( min != values.end() && *min <= funValues[i+1] ) + { + max = values.upper_bound( funValues[i+1] ); // greater than funValues[i+1], or end() + nbEvents[i] = std::distance( min, max ); + min = max; + } + } +} + //======================================================================= //function : GetValue //purpose : @@ -313,6 +397,246 @@ SMDSAbs_ElementType Volume::GetType() const } +/* + Class : MaxElementLength2D + Description : Functor calculating maximum length of 2D element +*/ + +double MaxElementLength2D::GetValue( long theElementId ) +{ + TSequenceOfXYZ P; + if( GetPoints( theElementId, P ) ) { + double aVal = 0; + const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId ); + SMDSAbs_ElementType aType = aElem->GetType(); + int len = P.size(); + switch( aType ) { + case SMDSAbs_Face: + if( len == 3 ) { // triangles + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 1 )); + aVal = Max(L1,Max(L2,L3)); + break; + } + else if( len == 4 ) { // quadrangles + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 1 )); + double D1 = getDistance(P( 1 ),P( 3 )); + double D2 = getDistance(P( 2 ),P( 4 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2)); + break; + } + else if( len == 6 ) { // quadratic triangles + double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 )); + double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 )); + double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 )); + aVal = Max(L1,Max(L2,L3)); + break; + } + else if( len == 8 ) { // quadratic quadrangles + double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 )); + double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 )); + double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 )); + double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 )); + double D1 = getDistance(P( 1 ),P( 5 )); + double D2 = getDistance(P( 3 ),P( 7 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2)); + break; + } + } + + if( myPrecision >= 0 ) + { + double prec = pow( 10., (double)myPrecision ); + aVal = floor( aVal * prec + 0.5 ) / prec; + } + return aVal; + } + return 0.; +} + +double MaxElementLength2D::GetBadRate( double Value, int /*nbNodes*/ ) const +{ + return Value; +} + +SMDSAbs_ElementType MaxElementLength2D::GetType() const +{ + return SMDSAbs_Face; +} + +/* + Class : MaxElementLength3D + Description : Functor calculating maximum length of 3D element +*/ + +double MaxElementLength3D::GetValue( long theElementId ) +{ + TSequenceOfXYZ P; + if( GetPoints( theElementId, P ) ) { + double aVal = 0; + const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId ); + SMDSAbs_ElementType aType = aElem->GetType(); + int len = P.size(); + switch( aType ) { + case SMDSAbs_Volume: + if( len == 4 ) { // tetras + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 1 )); + double L4 = getDistance(P( 1 ),P( 4 )); + double L5 = getDistance(P( 2 ),P( 4 )); + double L6 = getDistance(P( 3 ),P( 4 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + break; + } + else if( len == 5 ) { // pyramids + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 1 )); + double L5 = getDistance(P( 1 ),P( 5 )); + double L6 = getDistance(P( 2 ),P( 5 )); + double L7 = getDistance(P( 3 ),P( 5 )); + double L8 = getDistance(P( 4 ),P( 5 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(L7,L8)); + break; + } + else if( len == 6 ) { // pentas + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 1 )); + double L4 = getDistance(P( 4 ),P( 5 )); + double L5 = getDistance(P( 5 ),P( 6 )); + double L6 = getDistance(P( 6 ),P( 4 )); + double L7 = getDistance(P( 1 ),P( 4 )); + double L8 = getDistance(P( 2 ),P( 5 )); + double L9 = getDistance(P( 3 ),P( 6 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(Max(L7,L8),L9)); + break; + } + else if( len == 8 ) { // hexas + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 1 )); + double L5 = getDistance(P( 5 ),P( 6 )); + double L6 = getDistance(P( 6 ),P( 7 )); + double L7 = getDistance(P( 7 ),P( 8 )); + double L8 = getDistance(P( 8 ),P( 5 )); + double L9 = getDistance(P( 1 ),P( 5 )); + double L10= getDistance(P( 2 ),P( 6 )); + double L11= getDistance(P( 3 ),P( 7 )); + double L12= getDistance(P( 4 ),P( 8 )); + double D1 = getDistance(P( 1 ),P( 7 )); + double D2 = getDistance(P( 2 ),P( 8 )); + double D3 = getDistance(P( 3 ),P( 5 )); + double D4 = getDistance(P( 4 ),P( 6 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10))); + aVal = Max(aVal,Max(L11,L12)); + aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4))); + break; + } + else if( len == 10 ) { // quadratic tetras + double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 )); + double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 )); + double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 )); + double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + break; + } + else if( len == 13 ) { // quadratic pyramids + double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 )); + double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 )); + double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 )); + double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 )); + double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(L7,L8)); + break; + } + else if( len == 15 ) { // quadratic pentas + double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 )); + double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 )); + double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 )); + double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 )); + double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 )); + double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 )); + double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(Max(L7,L8),L9)); + break; + } + else if( len == 20 ) { // quadratic hexas + double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 )); + double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 )); + double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 )); + double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 )); + double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 )); + double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 )); + double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 )); + double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 )); + double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 )); + double D1 = getDistance(P( 1 ),P( 7 )); + double D2 = getDistance(P( 2 ),P( 8 )); + double D3 = getDistance(P( 3 ),P( 5 )); + double D4 = getDistance(P( 4 ),P( 6 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10))); + aVal = Max(aVal,Max(L11,L12)); + aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4))); + break; + } + else if( len > 1 && aElem->IsPoly() ) { // polys + // get the maximum distance between all pairs of nodes + for( int i = 1; i <= len; i++ ) { + for( int j = 1; j <= len; j++ ) { + if( j > i ) { // optimization of the loop + double D = getDistance( P(i), P(j) ); + aVal = Max( aVal, D ); + } + } + } + } + } + + if( myPrecision >= 0 ) + { + double prec = pow( 10., (double)myPrecision ); + aVal = floor( aVal * prec + 0.5 ) / prec; + } + return aVal; + } + return 0.; +} + +double MaxElementLength3D::GetBadRate( double Value, int /*nbNodes*/ ) const +{ + return Value; +} + +SMDSAbs_ElementType MaxElementLength3D::GetType() const +{ + return SMDSAbs_Volume; +} + + /* Class : MinimumAngle Description : Functor for calculation of minimum angle @@ -408,47 +732,94 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P ) return alfa * maxLen * half_perimeter / anArea; } else if( nbNodes == 4 ) { // quadrangle - // return aspect ratio of the worst triange which can be built + // Compute lengths of the sides + std::vector< double > aLen (4); + aLen[0] = getDistance( P(1), P(2) ); + aLen[1] = getDistance( P(2), P(3) ); + aLen[2] = getDistance( P(3), P(4) ); + aLen[3] = getDistance( P(4), P(1) ); + // Compute lengths of the diagonals + std::vector< double > aDia (2); + aDia[0] = getDistance( P(1), P(3) ); + aDia[1] = getDistance( P(2), P(4) ); + // Compute areas of all triangles which can be built // taking three nodes of the quadrangle - TSequenceOfXYZ triaPnts(3); - // triangle on nodes 1 3 2 - triaPnts(1) = P(1); - triaPnts(2) = P(3); - triaPnts(3) = P(2); - double ar = GetValue( triaPnts ); - // triangle on nodes 1 3 4 - triaPnts(3) = P(4); - ar = Max ( ar, GetValue( triaPnts )); - // triangle on nodes 1 2 4 - triaPnts(2) = P(2); - ar = Max ( ar, GetValue( triaPnts )); - // triangle on nodes 3 2 4 - triaPnts(1) = P(3); - ar = Max ( ar, GetValue( triaPnts )); - - return ar; - } - else { // nbNodes==8 - quadratic quadrangle - // return aspect ratio of the worst triange which can be built + std::vector< double > anArea (4); + anArea[0] = getArea( P(1), P(2), P(3) ); + anArea[1] = getArea( P(1), P(2), P(4) ); + anArea[2] = getArea( P(1), P(3), P(4) ); + anArea[3] = getArea( P(2), P(3), P(4) ); + // Q = alpha * L * C1 / C2, where + // + // alpha = sqrt( 1/32 ) + // L = max( L1, L2, L3, L4, D1, D2 ) + // C1 = sqrt( ( L1^2 + L1^2 + L1^2 + L1^2 ) / 4 ) + // C2 = min( S1, S2, S3, S4 ) + // Li - lengths of the edges + // Di - lengths of the diagonals + // Si - areas of the triangles + const double alpha = sqrt( 1 / 32. ); + double L = Max( aLen[ 0 ], + Max( aLen[ 1 ], + Max( aLen[ 2 ], + Max( aLen[ 3 ], + Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) ); + double C1 = sqrt( ( aLen[0] * aLen[0] + + aLen[1] * aLen[1] + + aLen[2] * aLen[2] + + aLen[3] * aLen[3] ) / 4. ); + double C2 = Min( anArea[ 0 ], + Min( anArea[ 1 ], + Min( anArea[ 2 ], anArea[ 3 ] ) ) ); + if ( C2 <= Precision::Confusion() ) + return 0.; + return alpha * L * C1 / C2; + } + else if( nbNodes == 8 ){ // nbNodes==8 - quadratic quadrangle + // Compute lengths of the sides + std::vector< double > aLen (4); + aLen[0] = getDistance( P(1), P(3) ); + aLen[1] = getDistance( P(3), P(5) ); + aLen[2] = getDistance( P(5), P(7) ); + aLen[3] = getDistance( P(7), P(1) ); + // Compute lengths of the diagonals + std::vector< double > aDia (2); + aDia[0] = getDistance( P(1), P(5) ); + aDia[1] = getDistance( P(3), P(7) ); + // Compute areas of all triangles which can be built // taking three nodes of the quadrangle - TSequenceOfXYZ triaPnts(3); - // triangle on nodes 1 3 2 - triaPnts(1) = P(1); - triaPnts(2) = P(5); - triaPnts(3) = P(3); - double ar = GetValue( triaPnts ); - // triangle on nodes 1 3 4 - triaPnts(3) = P(7); - ar = Max ( ar, GetValue( triaPnts )); - // triangle on nodes 1 2 4 - triaPnts(2) = P(3); - ar = Max ( ar, GetValue( triaPnts )); - // triangle on nodes 3 2 4 - triaPnts(1) = P(5); - ar = Max ( ar, GetValue( triaPnts )); - - return ar; + std::vector< double > anArea (4); + anArea[0] = getArea( P(1), P(3), P(5) ); + anArea[1] = getArea( P(1), P(3), P(7) ); + anArea[2] = getArea( P(1), P(5), P(7) ); + anArea[3] = getArea( P(3), P(5), P(7) ); + // Q = alpha * L * C1 / C2, where + // + // alpha = sqrt( 1/32 ) + // L = max( L1, L2, L3, L4, D1, D2 ) + // C1 = sqrt( ( L1^2 + L1^2 + L1^2 + L1^2 ) / 4 ) + // C2 = min( S1, S2, S3, S4 ) + // Li - lengths of the edges + // Di - lengths of the diagonals + // Si - areas of the triangles + const double alpha = sqrt( 1 / 32. ); + double L = Max( aLen[ 0 ], + Max( aLen[ 1 ], + Max( aLen[ 2 ], + Max( aLen[ 3 ], + Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) ); + double C1 = sqrt( ( aLen[0] * aLen[0] + + aLen[1] * aLen[1] + + aLen[2] * aLen[2] + + aLen[3] * aLen[3] ) / 4. ); + double C2 = Min( anArea[ 0 ], + Min( anArea[ 1 ], + Min( anArea[ 2 ], anArea[ 3 ] ) ) ); + if ( C2 <= Precision::Confusion() ) + return 0.; + return alpha * L * C1 / C2; } + return 0; } double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const @@ -964,16 +1335,20 @@ SMDSAbs_ElementType Skew::GetType() const */ double Area::GetValue( const TSequenceOfXYZ& P ) { - gp_Vec aVec1( P(2) - P(1) ); - gp_Vec aVec2( P(3) - P(1) ); - gp_Vec SumVec = aVec1 ^ aVec2; - for (int i=4; i<=P.size(); i++) { - gp_Vec aVec1( P(i-1) - P(1) ); - gp_Vec aVec2( P(i) - P(1) ); - gp_Vec tmp = aVec1 ^ aVec2; - SumVec.Add(tmp); + double val = 0.0; + if ( P.size() > 2 ) { + gp_Vec aVec1( P(2) - P(1) ); + gp_Vec aVec2( P(3) - P(1) ); + gp_Vec SumVec = aVec1 ^ aVec2; + for (int i=4; i<=P.size(); i++) { + gp_Vec aVec1( P(i-1) - P(1) ); + gp_Vec aVec2( P(i) - P(1) ); + gp_Vec tmp = aVec1 ^ aVec2; + SumVec.Add(tmp); + } + val = SumVec.Magnitude() * 0.5; } - return SumVec.Magnitude() * 0.5; + return val; } double Area::GetBadRate( double Value, int /*nbNodes*/ ) const @@ -1090,7 +1465,7 @@ double Length2D::GetValue( long theElementId) else if (len == 5){ // piramids double L1 = getDistance(P( 1 ),P( 2 )); double L2 = getDistance(P( 2 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 1 )); + double L3 = getDistance(P( 3 ),P( 4 )); double L4 = getDistance(P( 4 ),P( 1 )); double L5 = getDistance(P( 1 ),P( 5 )); double L6 = getDistance(P( 2 ),P( 5 )); @@ -1150,7 +1525,7 @@ double Length2D::GetValue( long theElementId) else if (len == 13){ // quadratic piramids double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 )); double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 1 )); + double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 )); double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 )); double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 )); double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 )); @@ -2002,13 +2377,71 @@ SMDSAbs_GeometryType ElemGeomType::GetGeomType() const return myGeomType; } +//================================================================================ +/*! + * \brief Class CoplanarFaces + */ +//================================================================================ + +CoplanarFaces::CoplanarFaces() + : myMesh(0), myFaceID(0), myToler(0) +{ +} +bool CoplanarFaces::IsSatisfy( long theElementId ) +{ + if ( myCoplanarIDs.empty() ) + { + // Build a set of coplanar face ids + + if ( !myMesh || !myFaceID || !myToler ) + return false; + + const SMDS_MeshElement* face = myMesh->FindElement( myFaceID ); + if ( !face || face->GetType() != SMDSAbs_Face ) + return false; + + bool normOK; + gp_Vec myNorm = getNormale( static_cast(face), &normOK ); + if (!normOK) + return false; + + const double radianTol = myToler * PI180; + typedef SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > TFaceIt; + std::set checkedFaces, checkedNodes; + std::list faceQueue( 1, face ); + while ( !faceQueue.empty() ) + { + face = faceQueue.front(); + if ( checkedFaces.insert( face ).second ) + { + gp_Vec norm = getNormale( static_cast(face), &normOK ); + if (!normOK || myNorm.Angle( norm ) <= radianTol) + { + myCoplanarIDs.insert( face->GetID() ); + std::set neighborFaces; + for ( int i = 0; i < face->NbCornerNodes(); ++i ) + { + const SMDS_MeshNode* n = face->GetNode( i ); + if ( checkedNodes.insert( n ).second ) + neighborFaces.insert( TFaceIt( n->GetInverseElementIterator(SMDSAbs_Face)), + TFaceIt()); + } + faceQueue.insert( faceQueue.end(), neighborFaces.begin(), neighborFaces.end() ); + } + } + faceQueue.pop_front(); + } + } + return myCoplanarIDs.count( theElementId ); +} + /* - Class : RangeOfIds - Description : Predicate for Range of Ids. - Range may be specified with two ways. - 1. Using AddToRange method - 2. With SetRangeStr method. Parameter of this method is a string - like as "1,2,3,50-60,63,67,70-" + *Class : RangeOfIds + *Description : Predicate for Range of Ids. + * Range may be specified with two ways. + * 1. Using AddToRange method + * 2. With SetRangeStr method. Parameter of this method is a string + * like as "1,2,3,50-60,63,67,70-" */ //======================================================================= @@ -2638,32 +3071,6 @@ static void getLinks( const SMDS_MeshFace* theFace, } } -static gp_XYZ getNormale( const SMDS_MeshFace* theFace ) -{ - gp_XYZ n; - int aNbNode = theFace->NbNodes(); - TColgp_Array1OfXYZ anArrOfXYZ(1,4); - SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator(); - int i = 1; - for ( ; aNodeItr->more() && i <= 4; i++ ) { - SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next(); - anArrOfXYZ.SetValue(i, gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) ); - } - - gp_XYZ q1 = anArrOfXYZ.Value(2) - anArrOfXYZ.Value(1); - gp_XYZ q2 = anArrOfXYZ.Value(3) - anArrOfXYZ.Value(1); - n = q1 ^ q2; - if ( aNbNode > 3 ) { - gp_XYZ q3 = anArrOfXYZ.Value(4) - anArrOfXYZ.Value(1); - n += q2 ^ q3; - } - double len = n.Modulus(); - if ( len > 0 ) - n /= len; - - return n; -} - bool ManifoldPart::findConnected ( const ManifoldPart::TDataMapFacePtrInt& theAllFacePtrInt, SMDS_MeshFace* theStartFace, diff --git a/src/Controls/SMESH_ControlsDef.hxx b/src/Controls/SMESH_ControlsDef.hxx index 5849c1f83..915bd9f4b 100644 --- a/src/Controls/SMESH_ControlsDef.hxx +++ b/src/Controls/SMESH_ControlsDef.hxx @@ -127,6 +127,9 @@ namespace SMESH{ virtual void SetMesh( const SMDS_Mesh* theMesh ); virtual double GetValue( long theElementId ); virtual double GetValue(const TSequenceOfXYZ& thePoints) { return -1.0;}; + void GetHistogram(int nbIntervals, + std::vector& nbEvents, + std::vector& funValues); virtual SMDSAbs_ElementType GetType() const = 0; virtual double GetBadRate( double Value, int nbNodes ) const = 0; long GetPrecision() const; @@ -156,6 +159,30 @@ namespace SMESH{ }; + /* + Class : MaxElementLength2D + Description : Functor calculating maximum length of 2D element + */ + class SMESHCONTROLS_EXPORT MaxElementLength2D: public virtual NumericalFunctor{ + public: + virtual double GetValue( long theElementId ); + virtual double GetBadRate( double Value, int nbNodes ) const; + virtual SMDSAbs_ElementType GetType() const; + }; + + + /* + Class : MaxElementLength3D + Description : Functor calculating maximum length of 3D element + */ + class SMESHCONTROLS_EXPORT MaxElementLength3D: public virtual NumericalFunctor{ + public: + virtual double GetValue( long theElementId ); + virtual double GetBadRate( double Value, int nbNodes ) const; + virtual SMDSAbs_ElementType GetType() const; + }; + + /* Class : SMESH_MinimumAngle Description : Functor for calculation of minimum angle @@ -770,11 +797,11 @@ namespace SMESH{ class SMESHCONTROLS_EXPORT ElemGeomType: public virtual Predicate{ public: ElemGeomType(); - virtual void SetMesh( const SMDS_Mesh* theMesh ); - virtual bool IsSatisfy( long theElementId ); - void SetType( SMDSAbs_ElementType theType ); - virtual SMDSAbs_ElementType GetType() const; - void SetGeomType( SMDSAbs_GeometryType theType ); + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theElementId ); + void SetType( SMDSAbs_ElementType theType ); + virtual SMDSAbs_ElementType GetType() const; + void SetGeomType( SMDSAbs_GeometryType theType ); virtual SMDSAbs_GeometryType GetGeomType() const; private: @@ -784,6 +811,31 @@ namespace SMESH{ }; typedef boost::shared_ptr ElemGeomTypePtr; + /* + Class : CoplanarFaces + Description : Predicate to check angle between faces + */ + class SMESHCONTROLS_EXPORT CoplanarFaces: public virtual Predicate + { + public: + CoplanarFaces(); + void SetFace( long theID ) { myFaceID = theID; } + long GetFace() const { return myFaceID; } + void SetTolerance (const double theToler) { myToler = theToler; } + double GetTolerance () const { return myToler; } + virtual void SetMesh( const SMDS_Mesh* theMesh ) { myMesh = theMesh; } + virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Face; } + + virtual bool IsSatisfy( long theElementId ); + + private: + const SMDS_Mesh* myMesh; + long myFaceID; + double myToler; + std::set< long > myCoplanarIDs; + }; + typedef boost::shared_ptr CoplanarFacesPtr; + /* FILTER */ diff --git a/src/DriverUNV/DriverUNV_R_SMDS_Mesh.cxx b/src/DriverUNV/DriverUNV_R_SMDS_Mesh.cxx index bfb1d6394..24150eeda 100644 --- a/src/DriverUNV/DriverUNV_R_SMDS_Mesh.cxx +++ b/src/DriverUNV/DriverUNV_R_SMDS_Mesh.cxx @@ -95,20 +95,24 @@ Driver_Mesh::Status DriverUNV_R_SMDS_Mesh::Perform() } else if(IsFace(aRec.fe_descriptor_id)) { switch(aRec.fe_descriptor_id){ - case 71: // TRI3 - case 72: - case 74: - - case 41: // Plane Stress Linear Triangle - TRI3 - case 91: // Thin Shell Linear Triangle - TRI3 + case 41: // Plane Stress Linear Triangle + case 51: // Plane Strain Linear Triangle + case 61: // Plate Linear Triangle + case 74: // Membrane Linear Triangle + case 81: // Axisymetric Solid Linear Triangle + case 91: // Thin Shell Linear Triangle anElement = myMesh->AddFaceWithID(aRec.node_labels[0], aRec.node_labels[1], aRec.node_labels[2], aLabel); break; - case 42: // Plane Stress Quadratic Triangle - TRI6 - case 92: // Thin Shell Quadratic Triangle - TRI6 + case 42: // Plane Stress Parabolic Triangle + case 52: // Plane Strain Parabolic Triangle + case 62: // Plate Parabolic Triangle + case 72: // Membrane Parabolic Triangle + case 82: // Axisymetric Solid Parabolic Triangle + case 92: // Thin Shell Parabolic Triangle anElement = myMesh->AddFaceWithID(aRec.node_labels[0], aRec.node_labels[2], aRec.node_labels[4], @@ -118,8 +122,12 @@ Driver_Mesh::Status DriverUNV_R_SMDS_Mesh::Perform() aLabel); break; - case 44: // Plane Stress Linear Quadrilateral - QUAD4 - case 94: // Thin Shell Linear Quadrilateral - QUAD4 + case 44: // Plane Stress Linear Quadrilateral + case 54: // Plane Strain Linear Quadrilateral + case 64: // Plate Linear Quadrilateral + case 71: // Membrane Linear Quadrilateral + case 84: // Axisymetric Solid Linear Quadrilateral + case 94: // Thin Shell Linear Quadrilateral anElement = myMesh->AddFaceWithID(aRec.node_labels[0], aRec.node_labels[1], aRec.node_labels[2], @@ -127,8 +135,12 @@ Driver_Mesh::Status DriverUNV_R_SMDS_Mesh::Perform() aLabel); break; - case 45: // Plane Stress Quadratic Quadrilateral - QUAD8 - case 95: // Thin Shell Quadratic Quadrilateral - QUAD8 + case 45: // Plane Stress Parabolic Quadrilateral + case 55: // Plane Strain Parabolic Quadrilateral + case 65: // Plate Parabolic Quadrilateral + case 75: // Membrane Parabolic Quadrilateral + case 85: // Axisymetric Solid Parabolic Quadrilateral + case 95: // Thin Shell Parabolic Quadrilateral anElement = myMesh->AddFaceWithID(aRec.node_labels[0], aRec.node_labels[2], aRec.node_labels[4], diff --git a/src/DriverUNV/UNV2412_Structure.cxx b/src/DriverUNV/UNV2412_Structure.cxx index 893fa2391..35cb62afe 100644 --- a/src/DriverUNV/UNV2412_Structure.cxx +++ b/src/DriverUNV/UNV2412_Structure.cxx @@ -30,11 +30,155 @@ using namespace std; using namespace UNV; using namespace UNV2412; -#ifdef _DEBUG_ -static int MYDEBUG = 1; -#else -static int MYDEBUG = 0; -#endif +// Universal Dataset Number 2412 + +// Name: Elements +// Status: Current +// Owner: Simulation +// Revision Date: 14-AUG-1992 +// ----------------------------------------------------------------------- + +// Record 1: FORMAT(6I10) +// Field 1 -- element label +// Field 2 -- fe descriptor id +// Field 3 -- physical property table number +// Field 4 -- material property table number +// Field 5 -- color +// Field 6 -- number of nodes on element + +// Record 2: *** FOR NON-BEAM ELEMENTS *** +// FORMAT(8I10) +// Fields 1-n -- node labels defining element + +// Record 2: *** FOR BEAM ELEMENTS ONLY *** +// FORMAT(3I10) +// Field 1 -- beam orientation node number +// Field 2 -- beam fore-end cross section number +// Field 3 -- beam aft-end cross section number + +// Record 3: *** FOR BEAM ELEMENTS ONLY *** +// FORMAT(8I10) +// Fields 1-n -- node labels defining element + +// Records 1 and 2 are repeated for each non-beam element in the model. +// Records 1 - 3 are repeated for each beam element in the model. + +// Example: + +// -1 +// 2412 +// 1 11 1 5380 7 2 +// 0 1 1 +// 1 2 +// 2 21 2 5380 7 2 +// 0 1 1 +// 3 4 +// 3 22 3 5380 7 2 +// 0 1 2 +// 5 6 +// 6 91 6 5380 7 3 +// 11 18 12 +// 9 95 6 5380 7 8 +// 22 25 29 30 31 26 24 23 +// 14 136 8 0 7 2 +// 53 54 +// 36 116 16 5380 7 20 +// 152 159 168 167 166 158 150 151 +// 154 170 169 153 157 161 173 172 +// 171 160 155 156 +// -1 + +// FE Descriptor Id definitions +// ____________________________ + +// 11 Rod +// 21 Linear beam +// 22 Tapered beam +// 23 Curved beam +// 24 Parabolic beam +// 31 Straight pipe +// 32 Curved pipe +// 41 Plane Stress Linear Triangle +// 42 Plane Stress Parabolic Triangle +// 43 Plane Stress Cubic Triangle +// 44 Plane Stress Linear Quadrilateral +// 45 Plane Stress Parabolic Quadrilateral +// 46 Plane Strain Cubic Quadrilateral +// 51 Plane Strain Linear Triangle +// 52 Plane Strain Parabolic Triangle +// 53 Plane Strain Cubic Triangle +// 54 Plane Strain Linear Quadrilateral +// 55 Plane Strain Parabolic Quadrilateral +// 56 Plane Strain Cubic Quadrilateral +// 61 Plate Linear Triangle +// 62 Plate Parabolic Triangle +// 63 Plate Cubic Triangle +// 64 Plate Linear Quadrilateral +// 65 Plate Parabolic Quadrilateral +// 66 Plate Cubic Quadrilateral +// 71 Membrane Linear Quadrilateral +// 72 Membrane Parabolic Triangle +// 73 Membrane Cubic Triangle +// 74 Membrane Linear Triangle +// 75 Membrane Parabolic Quadrilateral +// 76 Membrane Cubic Quadrilateral +// 81 Axisymetric Solid Linear Triangle +// 82 Axisymetric Solid Parabolic Triangle +// 84 Axisymetric Solid Linear Quadrilateral +// 85 Axisymetric Solid Parabolic Quadrilateral +// 91 Thin Shell Linear Triangle +// 92 Thin Shell Parabolic Triangle +// 93 Thin Shell Cubic Triangle +// 94 Thin Shell Linear Quadrilateral +// 95 Thin Shell Parabolic Quadrilateral +// 96 Thin Shell Cubic Quadrilateral +// 101 Thick Shell Linear Wedge +// 102 Thick Shell Parabolic Wedge +// 103 Thick Shell Cubic Wedge +// 104 Thick Shell Linear Brick +// 105 Thick Shell Parabolic Brick +// 106 Thick Shell Cubic Brick +// 111 Solid Linear Tetrahedron +// 112 Solid Linear Wedge +// 113 Solid Parabolic Wedge +// 114 Solid Cubic Wedge +// 115 Solid Linear Brick +// 116 Solid Parabolic Brick +// 117 Solid Cubic Brick +// 118 Solid Parabolic Tetrahedron +// 121 Rigid Bar +// 122 Rigid Element +// 136 Node To Node Translational Spring +// 137 Node To Node Rotational Spring +// 138 Node To Ground Translational Spring +// 139 Node To Ground Rotational Spring +// 141 Node To Node Damper +// 142 Node To Gound Damper +// 151 Node To Node Gap +// 152 Node To Ground Gap +// 161 Lumped Mass +// 171 Axisymetric Linear Shell +// 172 Axisymetric Parabolic Shell +// 181 Constraint +// 191 Plastic Cold Runner +// 192 Plastic Hot Runner +// 193 Plastic Water Line +// 194 Plastic Fountain +// 195 Plastic Baffle +// 196 Plastic Rod Heater +// 201 Linear node-to-node interface +// 202 Linear edge-to-edge interface +// 203 Parabolic edge-to-edge interface +// 204 Linear face-to-face interface +// 208 Parabolic face-to-face interface +// 212 Linear axisymmetric interface +// 213 Parabolic axisymmetric interface +// 221 Linear rigid surface +// 222 Parabolic rigin surface +// 231 Axisymetric linear rigid surface +// 232 Axisymentric parabolic rigid surface + + static string _label_dataset = "2412"; @@ -158,31 +302,34 @@ bool UNV2412::IsBeam(int theFeDescriptorId){ bool UNV2412::IsFace(int theFeDescriptorId){ - switch (theFeDescriptorId){ + return ( 41 <= theFeDescriptorId && theFeDescriptorId <= 96 ); +// switch (theFeDescriptorId){ - case 71: // TRI3 - case 72: - case 74: +// case 71: // TRI3 +// case 72: +// case 74: - case 41: // Plane Stress Linear Triangle - TRI3 - case 91: // Thin Shell Linear Triangle - TRI3 +// case 41: // Plane Stress Linear Triangle - TRI3 +// case 51: // Plane Strain Linear Triangle +// case 91: // Thin Shell Linear Triangle - TRI3 - case 42: // Plane Stress Quadratic Triangle - TRI6 - case 92: // Thin Shell Quadratic Triangle - TRI6 +// case 42: // Plane Stress Quadratic Triangle - TRI6 +// case 52: // Plane Strain Parabolic Triangle +// case 92: // Thin Shell Quadratic Triangle - TRI6 - case 43: // Plane Stress Cubic Triangle +// case 43: // Plane Stress Cubic Triangle - case 44: // Plane Stress Linear Quadrilateral - QUAD4 - case 94: // Thin Shell Linear Quadrilateral - QUAD4 +// case 44: // Plane Stress Linear Quadrilateral - QUAD4 +// case 94: // Thin Shell Linear Quadrilateral - QUAD4 - case 45: // Plane Stress Quadratic Quadrilateral - QUAD8 - case 95: // Thin Shell Quadratic Quadrilateral - QUAD8 +// case 45: // Plane Stress Quadratic Quadrilateral - QUAD8 +// case 95: // Thin Shell Quadratic Quadrilateral - QUAD8 - case 46: // Plane Stress Cubic Quadrilateral +// case 46: // Plane Stress Cubic Quadrilateral - return true; - } - return false; +// return true; +// } +// return false; } diff --git a/src/DriverUNV/UNV2417_Structure.cxx b/src/DriverUNV/UNV2417_Structure.cxx index 0f7313b76..822e22470 100644 --- a/src/DriverUNV/UNV2417_Structure.cxx +++ b/src/DriverUNV/UNV2417_Structure.cxx @@ -30,13 +30,6 @@ using namespace std; using namespace UNV; using namespace UNV2417; -#ifdef _DEBUG_ -static int MYDEBUG = 0; -#else -static int MYDEBUG = 0; -#endif - - static string _group_labels[] = {"2417", "2429", "2430", "2432", "2435", "2452", "2467", "2477"}; #define NBGROUP 8 diff --git a/src/DriverUNV/UNV_Test.cxx b/src/DriverUNV/UNV_Test.cxx index 55964109a..295363380 100644 --- a/src/DriverUNV/UNV_Test.cxx +++ b/src/DriverUNV/UNV_Test.cxx @@ -29,13 +29,6 @@ using namespace std; -#ifdef DEBUG -static int MYDEBUG = 1; -#else -static int MYDEBUG = 0; -#endif - - void ReadMed(const char* theFileName){ std::ifstream in_stream(theFileName); diff --git a/src/DriverUNV/UNV_Utilities.cxx b/src/DriverUNV/UNV_Utilities.cxx index 7a23dfd76..4cd3a4167 100644 --- a/src/DriverUNV/UNV_Utilities.cxx +++ b/src/DriverUNV/UNV_Utilities.cxx @@ -24,12 +24,6 @@ using namespace std; -#ifdef _DEBUG_ -static int MYDEBUG = 1; -#else -static int MYDEBUG = 0; -#endif - int UNV::PrefixPrinter::myCounter = 0; diff --git a/src/Makefile.am b/src/Makefile.am index c77ff62a0..e244fbde6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,7 +40,8 @@ SUBDIRS = \ SMESH_SWIG \ MEFISTO2 \ StdMeshers \ - StdMeshers_I + StdMeshers_I \ + SMESH_PY if SMESH_ENABLE_GUI SUBDIRS += \ @@ -54,4 +55,4 @@ endif DIST_SUBDIRS = SMDS SMESHDS Controls Driver DriverMED DriverDAT DriverUNV DriverSTL SMESH \ SMESH_I SMESHClient SMESH_SWIG MEFISTO2 StdMeshers StdMeshers_I OBJECT \ - SMESHFiltersSelection SMESHGUI PluginUtils SMESH_SWIG_WITHIHM StdMeshersGUI + SMESHFiltersSelection SMESHGUI PluginUtils SMESH_SWIG_WITHIHM StdMeshersGUI SMESH_PY diff --git a/src/OBJECT/Makefile.am b/src/OBJECT/Makefile.am index 0e8cdabd9..219350562 100644 --- a/src/OBJECT/Makefile.am +++ b/src/OBJECT/Makefile.am @@ -34,7 +34,9 @@ salomeinclude_HEADERS = \ SMESH_DeviceActor.h \ SMESH_PreviewActorsCollection.h \ SMESH_ExtractGeometry.h \ - SMESH_FaceOrientationFilter.h + SMESH_FaceOrientationFilter.h \ + SMESH_ScalarBarActor.h + # Libraries targets @@ -46,7 +48,8 @@ dist_libSMESHObject_la_SOURCES = \ SMESH_PreviewActorsCollection.cxx \ SMESH_ExtractGeometry.cxx \ SMESH_ActorUtils.cxx \ - SMESH_FaceOrientationFilter.cxx + SMESH_FaceOrientationFilter.cxx \ + SMESH_ScalarBarActor.cxx libSMESHObject_la_CPPFLAGS = \ $(QT_INCLUDES) \ diff --git a/src/OBJECT/SMESH_Actor.cxx b/src/OBJECT/SMESH_Actor.cxx index cd9e06919..4afc7f4ca 100644 --- a/src/OBJECT/SMESH_Actor.cxx +++ b/src/OBJECT/SMESH_Actor.cxx @@ -30,6 +30,8 @@ #include "SMESH_DeviceActor.h" #include "SMESH_ObjectDef.h" #include "SMESH_ControlsDef.hxx" +#include "SMESH_ScalarBarActor.h" +#include "VTKViewer_CellCenters.h" #include "VTKViewer_ExtractUnstructuredGrid.h" #include "VTKViewer_FramedTextActor.h" #include "SALOME_InteractiveObject.hxx" @@ -59,12 +61,10 @@ #include #include #include -#include #include #include #include -#include #include #include @@ -196,6 +196,7 @@ SMESH_ActorDef::SMESH_ActorDef() aFilter->RegisterCellsWithType(VTK_QUADRATIC_TETRA); aFilter->RegisterCellsWithType(VTK_QUADRATIC_HEXAHEDRON); aFilter->RegisterCellsWithType(VTK_QUADRATIC_WEDGE); + aFilter->RegisterCellsWithType(VTK_QUADRATIC_PYRAMID); aFilter->RegisterCellsWithType(VTK_CONVEX_POINT_SET); //Definition 1D device of the actor @@ -370,7 +371,7 @@ SMESH_ActorDef::SMESH_ActorDef() //Controls - Aspect Ratio: incorrect colors of the best and worst values myLookupTable->SetHueRange(0.667,0.0); - myScalarBarActor = vtkScalarBarActor::New(); + myScalarBarActor = SMESH_ScalarBarActor::New(); myScalarBarActor->SetVisibility(false); myScalarBarActor->SetLookupTable(myLookupTable); @@ -427,7 +428,7 @@ SMESH_ActorDef::SMESH_ActorDef() //--------------------------------------- myCellsNumDataSet = vtkUnstructuredGrid::New(); - myCellCenters = vtkCellCenters::New(); + myCellCenters = VTKViewer_CellCenters::New(); myCellCenters->SetInput(myCellsNumDataSet); myClsMaskPoints = vtkMaskPoints::New(); @@ -487,9 +488,11 @@ SMESH_ActorDef::SMESH_ActorDef() myHighlitableActor->SetQuadraticArcAngle(aQuadraticAngle); my2DActor->SetQuadraticArcAngle(aQuadraticAngle); - // Set color of the name actor + // Set colors of the name actor SMESH::GetColor( "SMESH", "fill_color", anRGB[0], anRGB[1], anRGB[2], QColor( 0, 170, 255 ) ); myNameActor->SetBackgroundColor(anRGB[0], anRGB[1], anRGB[2]); + SMESH::GetColor( "SMESH", "group_name_color", anRGB[0], anRGB[1], anRGB[2], QColor( 255, 255, 255 ) ); + myNameActor->SetForegroundColor(anRGB[0], anRGB[1], anRGB[2]); } @@ -497,6 +500,9 @@ SMESH_ActorDef::~SMESH_ActorDef() { if(MYDEBUG) MESSAGE("~SMESH_ActorDef - "<InvokeEvent( SMESH::DeleteActorEvent, NULL ); + myScalarBarActor->Delete(); myLookupTable->Delete(); @@ -718,51 +724,50 @@ SetControlMode(eControl theMode, bool anIsScalarVisible = theMode > eNone; if(anIsScalarVisible){ - SMESH::Controls::FunctorPtr aFunctor; switch(theMode){ case eLength: { SMESH::Controls::Length* aControl = new SMESH::Controls::Length(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my1DActor; break; } case eLength2D: { - aFunctor.reset(new SMESH::Controls::Length2D()); + myFunctor.reset(new SMESH::Controls::Length2D()); myControlActor = my2DActor; break; } case eFreeBorders: - aFunctor.reset(new SMESH::Controls::FreeBorders()); + myFunctor.reset(new SMESH::Controls::FreeBorders()); myControlActor = my1DActor; break; case eFreeEdges: - aFunctor.reset(new SMESH::Controls::FreeEdges()); + myFunctor.reset(new SMESH::Controls::FreeEdges()); myControlActor = my2DActor; break; case eFreeNodes: - aFunctor.reset(new SMESH::Controls::FreeNodes()); + myFunctor.reset(new SMESH::Controls::FreeNodes()); myControlActor = myNodeActor; break; case eFreeFaces: - aFunctor.reset(new SMESH::Controls::FreeFaces()); + myFunctor.reset(new SMESH::Controls::FreeFaces()); myControlActor = my2DActor; break; case eMultiConnection: - aFunctor.reset(new SMESH::Controls::MultiConnection()); + myFunctor.reset(new SMESH::Controls::MultiConnection()); myControlActor = my1DActor; break; case eMultiConnection2D: - aFunctor.reset(new SMESH::Controls::MultiConnection2D()); + myFunctor.reset(new SMESH::Controls::MultiConnection2D()); myControlActor = my2DActor; break; case eArea: { SMESH::Controls::Area* aControl = new SMESH::Controls::Area(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my2DActor; break; } @@ -770,7 +775,7 @@ SetControlMode(eControl theMode, { SMESH::Controls::Taper* aControl = new SMESH::Controls::Taper(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my2DActor; break; } @@ -778,7 +783,7 @@ SetControlMode(eControl theMode, { SMESH::Controls::AspectRatio* aControl = new SMESH::Controls::AspectRatio(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my2DActor; break; } @@ -786,7 +791,7 @@ SetControlMode(eControl theMode, { SMESH::Controls::AspectRatio3D* aControl = new SMESH::Controls::AspectRatio3D(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my3DActor; break; } @@ -794,7 +799,23 @@ SetControlMode(eControl theMode, { SMESH::Controls::Volume* aControl = new SMESH::Controls::Volume(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); + myControlActor = my3DActor; + break; + } + case eMaxElementLength2D: + { + SMESH::Controls::MaxElementLength2D* aControl = new SMESH::Controls::MaxElementLength2D(); + aControl->SetPrecision( myControlsPrecision ); + myFunctor.reset( aControl ); + myControlActor = my2DActor; + break; + } + case eMaxElementLength3D: + { + SMESH::Controls::MaxElementLength3D* aControl = new SMESH::Controls::MaxElementLength3D(); + aControl->SetPrecision( myControlsPrecision ); + myFunctor.reset( aControl ); myControlActor = my3DActor; break; } @@ -802,7 +823,7 @@ SetControlMode(eControl theMode, { SMESH::Controls::MinimumAngle* aControl = new SMESH::Controls::MinimumAngle(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my2DActor; break; } @@ -810,7 +831,7 @@ SetControlMode(eControl theMode, { SMESH::Controls::Warping* aControl = new SMESH::Controls::Warping(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my2DActor; break; } @@ -818,7 +839,7 @@ SetControlMode(eControl theMode, { SMESH::Controls::Skew* aControl = new SMESH::Controls::Skew(); aControl->SetPrecision( myControlsPrecision ); - aFunctor.reset( aControl ); + myFunctor.reset( aControl ); myControlActor = my2DActor; break; } @@ -832,21 +853,21 @@ SetControlMode(eControl theMode, myControlMode = theMode; switch(myControlMode){ case eFreeNodes: - myNodeExtActor->SetExtControlMode(aFunctor); + myNodeExtActor->SetExtControlMode(myFunctor); break; case eFreeEdges: case eFreeBorders: - my1DExtActor->SetExtControlMode(aFunctor); + my1DExtActor->SetExtControlMode(myFunctor); break; case eFreeFaces: - my2DExtActor->SetExtControlMode(aFunctor); + my2DExtActor->SetExtControlMode(myFunctor); break; case eLength2D: case eMultiConnection2D: - my1DExtActor->SetExtControlMode(aFunctor,myScalarBarActor,myLookupTable); + my1DExtActor->SetExtControlMode(myFunctor,myScalarBarActor,myLookupTable); break; default: - myControlActor->SetControlMode(aFunctor,myScalarBarActor,myLookupTable); + myControlActor->SetControlMode(myFunctor,myScalarBarActor,myLookupTable); } } @@ -869,8 +890,11 @@ SetControlMode(eControl theMode, SetEntityMode(eVolumes); } - }else if(theCheckEntityMode){ - myEntityMode = eAllEntity; + } + else { + if(theCheckEntityMode) + myEntityMode = eAllEntity; + myFunctor.reset(); } SetRepresentation(GetRepresentation()); @@ -1344,6 +1368,7 @@ void SMESH_ActorDef::SetEntityMode(unsigned int theMode) aHightFilter->RegisterCellsWithType(VTK_QUADRATIC_TETRA); aHightFilter->RegisterCellsWithType(VTK_QUADRATIC_HEXAHEDRON); aHightFilter->RegisterCellsWithType(VTK_QUADRATIC_WEDGE); + aHightFilter->RegisterCellsWithType(VTK_QUADRATIC_PYRAMID); aHightFilter->RegisterCellsWithType(VTK_CONVEX_POINT_SET); } aFilter->Update(); @@ -1801,92 +1826,6 @@ GetClippingPlane(vtkIdType theID) return myCippingPlaneCont[theID].Get(); } - -static void ComputeBoundsParam(vtkDataSet* theDataSet, - vtkFloatingPointType theDirection[3], vtkFloatingPointType theMinPnt[3], - vtkFloatingPointType& theMaxBoundPrj, vtkFloatingPointType& theMinBoundPrj) -{ - vtkFloatingPointType aBounds[6]; - theDataSet->GetBounds(aBounds); - - //Enlarge bounds in order to avoid conflicts of precision - for(int i = 0; i < 6; i += 2){ - static double EPS = 1.0E-3; - vtkFloatingPointType aDelta = (aBounds[i+1] - aBounds[i])*EPS; - aBounds[i] -= aDelta; - aBounds[i+1] += aDelta; - } - - vtkFloatingPointType aBoundPoints[8][3] = { {aBounds[0],aBounds[2],aBounds[4]}, - {aBounds[1],aBounds[2],aBounds[4]}, - {aBounds[0],aBounds[3],aBounds[4]}, - {aBounds[1],aBounds[3],aBounds[4]}, - {aBounds[0],aBounds[2],aBounds[5]}, - {aBounds[1],aBounds[2],aBounds[5]}, - {aBounds[0],aBounds[3],aBounds[5]}, - {aBounds[1],aBounds[3],aBounds[5]}}; - - int aMaxId = 0, aMinId = aMaxId; - theMaxBoundPrj = vtkMath::Dot(theDirection,aBoundPoints[aMaxId]); - theMinBoundPrj = theMaxBoundPrj; - for(int i = 1; i < 8; i++){ - vtkFloatingPointType aTmp = vtkMath::Dot(theDirection,aBoundPoints[i]); - if(theMaxBoundPrj < aTmp){ - theMaxBoundPrj = aTmp; - aMaxId = i; - } - if(theMinBoundPrj > aTmp){ - theMinBoundPrj = aTmp; - aMinId = i; - } - } - vtkFloatingPointType *aMinPnt = aBoundPoints[aMaxId]; - theMinPnt[0] = aMinPnt[0]; - theMinPnt[1] = aMinPnt[1]; - theMinPnt[2] = aMinPnt[2]; -} - - -static void DistanceToPosition(vtkDataSet* theDataSet, - vtkFloatingPointType theDirection[3], vtkFloatingPointType theDist, vtkFloatingPointType thePos[3]) -{ - vtkFloatingPointType aMaxBoundPrj, aMinBoundPrj, aMinPnt[3]; - ComputeBoundsParam(theDataSet,theDirection,aMinPnt,aMaxBoundPrj,aMinBoundPrj); - vtkFloatingPointType aLength = (aMaxBoundPrj-aMinBoundPrj)*theDist; - thePos[0] = aMinPnt[0]-theDirection[0]*aLength; - thePos[1] = aMinPnt[1]-theDirection[1]*aLength; - thePos[2] = aMinPnt[2]-theDirection[2]*aLength; -} - - -static void PositionToDistance(vtkDataSet* theDataSet, - vtkFloatingPointType theDirection[3], vtkFloatingPointType thePos[3], vtkFloatingPointType& theDist) -{ - vtkFloatingPointType aMaxBoundPrj, aMinBoundPrj, aMinPnt[3]; - ComputeBoundsParam(theDataSet,theDirection,aMinPnt,aMaxBoundPrj,aMinBoundPrj); - vtkFloatingPointType aPrj = vtkMath::Dot(theDirection,thePos); - theDist = (aPrj-aMinBoundPrj)/(aMaxBoundPrj-aMinBoundPrj); -} - - -void SMESH_ActorDef::SetPlaneParam(vtkFloatingPointType theDir[3], vtkFloatingPointType theDist, vtkPlane* thePlane) -{ - thePlane->SetNormal(theDir); - vtkFloatingPointType anOrigin[3]; - ::DistanceToPosition(GetUnstructuredGrid(),theDir,theDist,anOrigin); - thePlane->SetOrigin(anOrigin); -} - - -void SMESH_ActorDef::GetPlaneParam(vtkFloatingPointType theDir[3], vtkFloatingPointType& theDist, vtkPlane* thePlane) -{ - thePlane->GetNormal(theDir); - - vtkFloatingPointType anOrigin[3]; - thePlane->GetOrigin(anOrigin); - ::PositionToDistance(GetUnstructuredGrid(),theDir,anOrigin,theDist); -} - void SMESH_ActorDef::UpdateScalarBar() { SUIT_ResourceMgr* mgr = SUIT_Session::session()->resourceMgr(); @@ -2000,6 +1939,21 @@ void SMESH_ActorDef::UpdateScalarBar() if( mgr->hasValue( "SMESH", "scalar_bar_num_colors" ) ) anIntVal = mgr->integerValue( "SMESH", "scalar_bar_num_colors", anIntVal ); myScalarBarActor->SetMaximumNumberOfColors( anIntVal == 0 ? 64 : anIntVal ); + + bool distributionVisibility = mgr->booleanValue("SMESH","distribution_visibility"); + myScalarBarActor->SetDistributionVisibility(distributionVisibility); + + 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]; + rgb[0]= distributionColor.red()/255.; + rgb[1]= distributionColor.green()/255.; + rgb[2]= distributionColor.blue()/255.; + myScalarBarActor->SetDistributionColor(rgb); + } diff --git a/src/OBJECT/SMESH_Actor.h b/src/OBJECT/SMESH_Actor.h index bb4e2fb68..24a57a00a 100644 --- a/src/OBJECT/SMESH_Actor.h +++ b/src/OBJECT/SMESH_Actor.h @@ -31,13 +31,20 @@ #include #include "SMESH_Object.h" +#include + class vtkUnstructuredGrid; -class vtkScalarBarActor; +class SMESH_ScalarBarActor; class vtkPlane; class vtkImplicitBoolean; +namespace SMESH +{ + const vtkIdType DeleteActorEvent = vtkCommand::UserEvent + 100; +} + class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor { static SMESH_Actor* New() { return NULL;} @@ -115,14 +122,13 @@ class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor enum eControl{eNone, eLength, eLength2D, eFreeBorders, eFreeEdges, eFreeNodes, eFreeFaces, eMultiConnection, eArea, eTaper, eAspectRatio, - eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D}; + eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D, + eMaxElementLength2D, eMaxElementLength3D}; virtual void SetControlMode(eControl theMode) = 0; virtual eControl GetControlMode() = 0; + virtual SMESH::Controls::FunctorPtr GetFunctor() = 0; - virtual vtkScalarBarActor* GetScalarBarActor() = 0; - - virtual void SetPlaneParam(vtkFloatingPointType theDir[3], vtkFloatingPointType theDist, vtkPlane* thePlane) = 0; - virtual void GetPlaneParam(vtkFloatingPointType theDir[3], vtkFloatingPointType& theDist, vtkPlane* thePlane) = 0; + virtual SMESH_ScalarBarActor* GetScalarBarActor() = 0; virtual void RemoveAllClippingPlanes() = 0; virtual vtkIdType GetNumberOfClippingPlanes() = 0; diff --git a/src/OBJECT/SMESH_ActorDef.h b/src/OBJECT/SMESH_ActorDef.h index e3d65ff7a..09b2232f0 100644 --- a/src/OBJECT/SMESH_ActorDef.h +++ b/src/OBJECT/SMESH_ActorDef.h @@ -59,23 +59,20 @@ class vtkPolyDataMapper; class vtkUnstructuredGrid; class vtkMergeFilter; class vtkPolyData; - class vtkMapper; class vtkActor2D; class vtkMaskPoints; -class vtkCellCenters; class vtkLabeledDataMapper; class vtkSelectVisiblePoints; - -class vtkScalarBarActor; class vtkLookupTable; - class vtkPlane; class vtkImplicitBoolean; - class vtkTimeStamp; +class VTKViewer_CellCenters; + class SMESH_DeviceActor; +class SMESH_ScalarBarActor; class SMESH_ActorDef : public SMESH_Actor @@ -184,11 +181,9 @@ class SMESH_ActorDef : public SMESH_Actor virtual void SetControlMode(eControl theMode); virtual eControl GetControlMode(){ return myControlMode;} + virtual SMESH::Controls::FunctorPtr GetFunctor() { return myFunctor; } - virtual vtkScalarBarActor* GetScalarBarActor(){ return myScalarBarActor;} - - virtual void SetPlaneParam(vtkFloatingPointType theDir[3], vtkFloatingPointType theDist, vtkPlane* thePlane); - virtual void GetPlaneParam(vtkFloatingPointType theDir[3], vtkFloatingPointType& theDist, vtkPlane* thePlane); + virtual SMESH_ScalarBarActor* GetScalarBarActor(){ return myScalarBarActor;} virtual void RemoveAllClippingPlanes(); virtual vtkIdType GetNumberOfClippingPlanes(); @@ -217,7 +212,7 @@ class SMESH_ActorDef : public SMESH_Actor TVisualObjPtr myVisualObj; vtkTimeStamp* myTimeStamp; - vtkScalarBarActor* myScalarBarActor; + SMESH_ScalarBarActor* myScalarBarActor; vtkLookupTable* myLookupTable; vtkProperty* mySurfaceProp; @@ -234,6 +229,7 @@ class SMESH_ActorDef : public SMESH_Actor SMESH_DeviceActor* myHighlitableActor; eControl myControlMode; + SMESH::Controls::FunctorPtr myFunctor; vtkProperty* my2DExtProp; SMESH_DeviceActor* my2DActor; SMESH_DeviceActor* my2DExtActor; @@ -271,7 +267,7 @@ class SMESH_ActorDef : public SMESH_Actor vtkUnstructuredGrid* myCellsNumDataSet; vtkActor2D *myCellsLabels; vtkMaskPoints* myClsMaskPoints; - vtkCellCenters* myCellCenters; + VTKViewer_CellCenters* myCellCenters; vtkLabeledDataMapper* myClsLabeledDataMapper; vtkSelectVisiblePoints* myClsSelectVisiblePoints; diff --git a/src/OBJECT/SMESH_DeviceActor.cxx b/src/OBJECT/SMESH_DeviceActor.cxx index 4be8cadec..600a4987c 100644 --- a/src/OBJECT/SMESH_DeviceActor.cxx +++ b/src/OBJECT/SMESH_DeviceActor.cxx @@ -26,6 +26,7 @@ // Module : SMESH // #include "SMESH_DeviceActor.h" +#include "SMESH_ScalarBarActor.h" #include "SMESH_ExtractGeometry.h" #include "SMESH_ControlsDef.hxx" #include "SMESH_ActorUtils.h" @@ -48,7 +49,6 @@ #include #include -#include #include #include #include @@ -282,7 +282,7 @@ SMESH_DeviceActor void SMESH_DeviceActor ::SetControlMode(SMESH::Controls::FunctorPtr theFunctor, - vtkScalarBarActor* theScalarBarActor, + SMESH_ScalarBarActor* theScalarBarActor, vtkLookupTable* theLookupTable) { bool anIsInitialized = theFunctor; @@ -310,6 +310,12 @@ SMESH_DeviceActor double aValue = aNumericalFunctor->GetValue(anObjId); aScalars->SetValue(i,aValue); } + int nbIntervals = theScalarBarActor->GetMaximumNumberOfColors(); + std::vector nbEvents; + std::vector funValues; + aNumericalFunctor->GetHistogram(nbIntervals, nbEvents, funValues); + theScalarBarActor->SetDistribution(nbEvents); + }else if(Predicate* aPredicate = dynamic_cast(theFunctor.get())){ for(vtkIdType i = 0; i < aNbCells; i++){ vtkIdType anId = myExtractUnstructuredGrid->GetInputId(i); @@ -336,7 +342,7 @@ SMESH_DeviceActor void SMESH_DeviceActor ::SetExtControlMode(SMESH::Controls::FunctorPtr theFunctor, - vtkScalarBarActor* theScalarBarActor, + SMESH_ScalarBarActor* theScalarBarActor, vtkLookupTable* theLookupTable) { bool anIsInitialized = theFunctor; @@ -469,6 +475,16 @@ SMESH_DeviceActor myMergeFilter->SetScalars(aDataSet); aDataSet->Delete(); } + + //Set Distribution + if(NumericalFunctor* aNumericalFunctor = dynamic_cast(theFunctor.get())){ + int nbIntervals = theScalarBarActor->GetMaximumNumberOfColors(); + std::vector nbEvents; + std::vector funValues; + aNumericalFunctor->GetHistogram(nbIntervals, nbEvents, funValues); + theScalarBarActor->SetDistribution(nbEvents); + } + } GetMapper()->SetScalarVisibility(anIsInitialized); theScalarBarActor->SetVisibility(anIsInitialized); diff --git a/src/OBJECT/SMESH_DeviceActor.h b/src/OBJECT/SMESH_DeviceActor.h index 7c506bd38..1e598fa84 100644 --- a/src/OBJECT/SMESH_DeviceActor.h +++ b/src/OBJECT/SMESH_DeviceActor.h @@ -42,7 +42,6 @@ class vtkProperty; class vtkMergeFilter; class vtkShrinkFilter; class vtkUnstructuredGrid; -class vtkScalarBarActor; class vtkLookupTable; class vtkImplicitBoolean; class vtkPassThroughFilter; @@ -54,6 +53,7 @@ class VTKViewer_PolyDataMapper; class SMESH_ExtractGeometry; class SMESH_FaceOrientationFilter; +class SMESH_ScalarBarActor; class SMESHOBJECT_EXPORT SMESH_DeviceActor: public vtkLODActor{ @@ -120,10 +120,10 @@ class SMESHOBJECT_EXPORT SMESH_DeviceActor: public vtkLODActor{ vtkUnstructuredGrid* GetUnstructuredGrid(); void SetControlMode(SMESH::Controls::FunctorPtr theFunctor, - vtkScalarBarActor* theScalarBarActor, + SMESH_ScalarBarActor* theScalarBarActor, vtkLookupTable* theLookupTable); void SetExtControlMode(SMESH::Controls::FunctorPtr theFunctor, - vtkScalarBarActor* theScalarBarActor, + SMESH_ScalarBarActor* theScalarBarActor, vtkLookupTable* theLookupTable); void SetExtControlMode(SMESH::Controls::FunctorPtr theFunctor); diff --git a/src/OBJECT/SMESH_FaceOrientationFilter.cxx b/src/OBJECT/SMESH_FaceOrientationFilter.cxx index 9f01d0bdc..d2407af6b 100644 --- a/src/OBJECT/SMESH_FaceOrientationFilter.cxx +++ b/src/OBJECT/SMESH_FaceOrientationFilter.cxx @@ -23,6 +23,8 @@ #include "SUIT_Session.h" #include "SUIT_ResourceMgr.h" +#include + #include #include #include @@ -33,7 +35,6 @@ #include #include #include -#include #include #include @@ -59,7 +60,7 @@ SMESH_FaceOrientationFilter::SMESH_FaceOrientationFilter() myFacePolyData = vtkPolyData::New(); - myFaceCenters = vtkCellCenters::New(); + myFaceCenters = VTKViewer_CellCenters::New(); myFaceCenters->SetInput(myFacePolyData); myFaceMaskPoints = vtkMaskPoints::New(); diff --git a/src/OBJECT/SMESH_FaceOrientationFilter.h b/src/OBJECT/SMESH_FaceOrientationFilter.h index 7a1721cb6..813468047 100644 --- a/src/OBJECT/SMESH_FaceOrientationFilter.h +++ b/src/OBJECT/SMESH_FaceOrientationFilter.h @@ -24,11 +24,12 @@ #include -class vtkCellCenters; class vtkGlyph3D; class vtkGlyphSource2D; class vtkMaskPoints; +class VTKViewer_CellCenters; + class SMESHOBJECT_EXPORT SMESH_FaceOrientationFilter : public vtkPolyDataAlgorithm { public: @@ -63,7 +64,7 @@ private: vtkFloatingPointType myOrientationScale; vtkPolyData* myArrowPolyData; vtkPolyData* myFacePolyData; - vtkCellCenters* myFaceCenters; + VTKViewer_CellCenters* myFaceCenters; vtkMaskPoints* myFaceMaskPoints; vtkGlyphSource2D* myGlyphSource; vtkGlyph3D* myBaseGlyph; diff --git a/src/OBJECT/SMESH_Object.cxx b/src/OBJECT/SMESH_Object.cxx index eb43a6b5f..480a0fe3f 100644 --- a/src/OBJECT/SMESH_Object.cxx +++ b/src/OBJECT/SMESH_Object.cxx @@ -119,7 +119,7 @@ static inline vtkIdType getCellType( const SMDSAbs_ElementType theType, return VTK_QUADRATIC_WEDGE; } else if ( theNbNodes==13 ) { - return VTK_CONVEX_POINT_SET; + return VTK_QUADRATIC_PYRAMID; //VTK_CONVEX_POINT_SET; } else return VTK_EMPTY_CELL; diff --git a/src/OBJECT/SMESH_PreviewActorsCollection.cxx b/src/OBJECT/SMESH_PreviewActorsCollection.cxx index d014af78c..059edd927 100644 --- a/src/OBJECT/SMESH_PreviewActorsCollection.cxx +++ b/src/OBJECT/SMESH_PreviewActorsCollection.cxx @@ -35,7 +35,6 @@ // VTK includes #include -#include #include #include #include diff --git a/src/OBJECT/SMESH_ScalarBarActor.cxx b/src/OBJECT/SMESH_ScalarBarActor.cxx new file mode 100644 index 000000000..3f7622672 --- /dev/null +++ b/src/OBJECT/SMESH_ScalarBarActor.cxx @@ -0,0 +1,923 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SMESH_ScalarBarActor.cxx +// Author : Roman NIKOLAEV +// Module : SMESH +// + +#include "SMESH_ScalarBarActor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHRINK_COEF 0.08; + +vtkStandardNewMacro(SMESH_ScalarBarActor); + +vtkCxxSetObjectMacro(SMESH_ScalarBarActor,LookupTable,vtkScalarsToColors); +vtkCxxSetObjectMacro(SMESH_ScalarBarActor,LabelTextProperty,vtkTextProperty); +vtkCxxSetObjectMacro(SMESH_ScalarBarActor,TitleTextProperty,vtkTextProperty); + +//---------------------------------------------------------------------------- +// Instantiate object with 64 maximum colors; 5 labels; %%-#6.3g label +// format, no title, and vertical orientation. The initial scalar bar +// size is (0.05 x 0.8) of the viewport size. +SMESH_ScalarBarActor::SMESH_ScalarBarActor() { + this->LookupTable = NULL; + this->Position2Coordinate->SetValue(0.17, 0.8); + + this->PositionCoordinate->SetCoordinateSystemToNormalizedViewport(); + this->PositionCoordinate->SetValue(0.82,0.1); + + this->MaximumNumberOfColors = 64; + this->NumberOfLabels = 5; + this->NumberOfLabelsBuilt = 0; + this->Orientation = VTK_ORIENT_VERTICAL; + this->Title = NULL; + + this->LabelTextProperty = vtkTextProperty::New(); + this->LabelTextProperty->SetFontSize(12); + this->LabelTextProperty->SetBold(1); + this->LabelTextProperty->SetItalic(1); + this->LabelTextProperty->SetShadow(1); + this->LabelTextProperty->SetFontFamilyToArial(); + + this->TitleTextProperty = vtkTextProperty::New(); + this->TitleTextProperty->ShallowCopy(this->LabelTextProperty); + + this->LabelFormat = new char[8]; + sprintf(this->LabelFormat,"%s","%-#6.3g"); + + this->TitleMapper = vtkTextMapper::New(); + this->TitleActor = vtkActor2D::New(); + this->TitleActor->SetMapper(this->TitleMapper); + this->TitleActor->GetPositionCoordinate()-> + SetReferenceCoordinate(this->PositionCoordinate); + + this->TextMappers = NULL; + this->TextActors = NULL; + + this->ScalarBar = vtkPolyData::New(); + this->ScalarBarMapper = vtkPolyDataMapper2D::New(); + this->ScalarBarMapper->SetInput(this->ScalarBar); + this->ScalarBarActor = vtkActor2D::New(); + this->ScalarBarActor->SetMapper(this->ScalarBarMapper); + this->ScalarBarActor->GetPositionCoordinate()-> + SetReferenceCoordinate(this->PositionCoordinate); + this->LastOrigin[0] = 0; + this->LastOrigin[1] = 0; + this->LastSize[0] = 0; + this->LastSize[1] = 0; + + + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + myDistribution = vtkPolyData::New(); + myDistributionMapper = vtkPolyDataMapper2D::New(); + myDistributionMapper->SetInput(this->myDistribution); + + myDistributionActor = vtkActor2D::New(); + myDistributionActor->SetMapper(this->myDistributionMapper); + myDistributionActor->GetPositionCoordinate()-> + SetReferenceCoordinate(this->PositionCoordinate); + + // By default distribution histogram is invisible + myDistributionActor->SetVisibility(0); + + // By default monocolor + myDistributionColoringType = SMESH_MONOCOLOR_TYPE; + // rnv end +} + +//---------------------------------------------------------------------------- +// Release any graphics resources that are being consumed by this actor. +// The parameter window could be used to determine which graphic +// resources to release. +void SMESH_ScalarBarActor::ReleaseGraphicsResources(vtkWindow *win) +{ + this->TitleActor->ReleaseGraphicsResources(win); + if (this->TextMappers != NULL ) + { + for (int i=0; i < this->NumberOfLabelsBuilt; i++) + { + this->TextActors[i]->ReleaseGraphicsResources(win); + } + } + this->ScalarBarActor->ReleaseGraphicsResources(win); + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + myDistributionActor->ReleaseGraphicsResources(win); +} + + +/*--------------------------------------------------------------------------*/ +SMESH_ScalarBarActor::~SMESH_ScalarBarActor() { + if (this->LabelFormat) + { + delete [] this->LabelFormat; + this->LabelFormat = NULL; + } + + this->TitleMapper->Delete(); + this->TitleActor->Delete(); + + if (this->TextMappers != NULL ) + { + for (int i=0; i < this->NumberOfLabelsBuilt; i++) + { + this->TextMappers[i]->Delete(); + this->TextActors[i]->Delete(); + } + delete [] this->TextMappers; + delete [] this->TextActors; + } + + this->ScalarBar->Delete(); + this->ScalarBarMapper->Delete(); + this->ScalarBarActor->Delete(); + + if (this->Title) + { + delete [] this->Title; + this->Title = NULL; + } + + this->SetLookupTable(NULL); + this->SetLabelTextProperty(NULL); + this->SetTitleTextProperty(NULL); + + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram: + myDistribution->Delete(); + myDistributionMapper->Delete(); + myDistributionActor->Delete(); + // rnv end +} + +//---------------------------------------------------------------------------- +int SMESH_ScalarBarActor::RenderOverlay(vtkViewport *viewport) +{ + int renderedSomething = 0; + int i; + + // Everything is built, just have to render + if (this->Title != NULL) + { + renderedSomething += this->TitleActor->RenderOverlay(viewport); + } + this->ScalarBarActor->RenderOverlay(viewport); + this->myDistributionActor->RenderOverlay(viewport); + if( this->TextActors == NULL) + { + vtkWarningMacro(<<"Need a mapper to render a scalar bar"); + return renderedSomething; + } + + for (i=0; iNumberOfLabels; i++) + { + renderedSomething += this->TextActors[i]->RenderOverlay(viewport); + } + + renderedSomething = (renderedSomething > 0)?(1):(0); + + return renderedSomething; +} + + +//---------------------------------------------------------------------------- +int SMESH_ScalarBarActor::RenderOpaqueGeometry(vtkViewport *viewport) +{ + int renderedSomething = 0; + int i; + int size[2]; + + if (!this->LookupTable) + { + vtkWarningMacro(<<"Need a mapper to render a scalar bar"); + return 0; + } + + if (!this->TitleTextProperty) + { + vtkErrorMacro(<<"Need title text property to render a scalar bar"); + return 0; + } + + if (!this->LabelTextProperty) + { + vtkErrorMacro(<<"Need label text property to render a scalar bar"); + return 0; + } + + // Check to see whether we have to rebuild everything + int positionsHaveChanged = 0; + if (viewport->GetMTime() > this->BuildTime || + (viewport->GetVTKWindow() && + viewport->GetVTKWindow()->GetMTime() > this->BuildTime)) + { + // if the viewport has changed we may - or may not need + // to rebuild, it depends on if the projected coords chage + int *barOrigin; + barOrigin = this->PositionCoordinate->GetComputedViewportValue(viewport); + size[0] = + this->Position2Coordinate->GetComputedViewportValue(viewport)[0] - + barOrigin[0]; + size[1] = + this->Position2Coordinate->GetComputedViewportValue(viewport)[1] - + barOrigin[1]; + if (this->LastSize[0] != size[0] || + this->LastSize[1] != size[1] || + this->LastOrigin[0] != barOrigin[0] || + this->LastOrigin[1] != barOrigin[1]) + { + positionsHaveChanged = 1; + } + } + + // Check to see whether we have to rebuild everything + if (positionsHaveChanged || + this->GetMTime() > this->BuildTime || + this->LookupTable->GetMTime() > this->BuildTime || + this->LabelTextProperty->GetMTime() > this->BuildTime || + this->TitleTextProperty->GetMTime() > this->BuildTime) + { + vtkDebugMacro(<<"Rebuilding subobjects"); + + // Delete previously constructed objects + // + if (this->TextMappers != NULL ) + { + for (i=0; i < this->NumberOfLabelsBuilt; i++) + { + this->TextMappers[i]->Delete(); + this->TextActors[i]->Delete(); + } + delete [] this->TextMappers; + delete [] this->TextActors; + } + + // Build scalar bar object; determine its type + // + // is this a vtkLookupTable or a subclass of vtkLookupTable + // with its scale set to log + // NOTE: it's possible we could to without the 'lut' variable + // later in the code, but if the vtkLookupTableSafeDownCast operation + // fails for some reason, this code will break in new ways. So, the 'LUT' + // variable is used for this operation only + vtkLookupTable *LUT = vtkLookupTable::SafeDownCast( this->LookupTable ); + int isLogTable = 0; + if ( LUT ) + { + if ( LUT->GetScale() == VTK_SCALE_LOG10 ) + { + isLogTable = 1; + } + } + + // we hard code how many steps to display + vtkScalarsToColors *lut = this->LookupTable; + int numColors = this->MaximumNumberOfColors; + double *range = lut->GetRange(); + + int numPts = 2*(numColors + 1); + vtkPoints *pts = vtkPoints::New(); + pts->SetNumberOfPoints(numPts); + vtkCellArray *polys = vtkCellArray::New(); + polys->Allocate(polys->EstimateSize(numColors,4)); + vtkUnsignedCharArray *colors = vtkUnsignedCharArray::New(); + colors->SetNumberOfComponents(3); + colors->SetNumberOfTuples(numColors); + + + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + bool distrVisibility = (numColors == this->myNbValues.size()); + vtkPoints *distrPts; + vtkCellArray *distrPolys; + vtkUnsignedCharArray *distColors = 0; + int numDistrPts = 0, numPositiveVal=0, maxValue=0; + if(!distrVisibility) + vtkDebugMacro(<<" Distribution invisible, because numColors == this->myNbValues.size()"); + + if (distrVisibility && GetDistributionVisibility()) { + for( i=0 ;iSetNumberOfPoints(numDistrPts); + distrPolys->Allocate(distrPolys->EstimateSize(numPositiveVal,4)); + this->myDistribution->Initialize(); + this->myDistribution->SetPoints(distrPts); + this->myDistribution->SetPolys(distrPolys); + distrPts->Delete(); + distrPolys->Delete(); + if ( myDistributionColoringType == SMESH_MULTICOLOR_TYPE ) { + distColors = vtkUnsignedCharArray::New(); + distColors->SetNumberOfComponents(3); + distColors->SetNumberOfTuples(numPositiveVal); + this->myDistribution->GetCellData()->SetScalars(distColors); + distColors->Delete(); + } else if( myDistributionColoringType == SMESH_MONOCOLOR_TYPE ){ + this->myDistribution->GetCellData()->SetScalars(NULL); + } + } else { + myDistribution->Reset(); + } + // rnv end + + this->ScalarBarActor->SetProperty(this->GetProperty()); + this->ScalarBar->Initialize(); + this->ScalarBar->SetPoints(pts); + this->ScalarBar->SetPolys(polys); + this->ScalarBar->GetCellData()->SetScalars(colors); + pts->Delete(); polys->Delete(); colors->Delete(); + + // get the viewport size in display coordinates + int *barOrigin, barWidth, barHeight, distrHeight; + barOrigin = this->PositionCoordinate->GetComputedViewportValue(viewport); + size[0] = + this->Position2Coordinate->GetComputedViewportValue(viewport)[0] - + barOrigin[0]; + size[1] = + this->Position2Coordinate->GetComputedViewportValue(viewport)[1] - + barOrigin[1]; + this->LastOrigin[0] = barOrigin[0]; + this->LastOrigin[1] = barOrigin[1]; + this->LastSize[0] = size[0]; + this->LastSize[1] = size[1]; + + // Update all the composing objects + this->TitleActor->SetProperty(this->GetProperty()); + this->TitleMapper->SetInput(this->Title); + if (this->TitleTextProperty->GetMTime() > this->BuildTime) + { + // Shallow copy here so that the size of the title prop is not affected + // by the automatic adjustment of its text mapper's size (i.e. its + // mapper's text property is identical except for the font size + // which will be modified later). This allows text actors to + // share the same text property, and in that case specifically allows + // the title and label text prop to be the same. + this->TitleMapper->GetTextProperty()->ShallowCopy(this->TitleTextProperty); + this->TitleMapper->GetTextProperty()->SetJustificationToCentered(); + } + + // find the best size for the title font + int titleSize[2]; + this->SizeTitle(titleSize, size, viewport); + + // find the best size for the ticks + int labelSize[2]; + this->AllocateAndSizeLabels(labelSize, size, viewport,range); + this->NumberOfLabelsBuilt = this->NumberOfLabels; + + // generate points + double x[3]; x[2] = 0.0; + double delta, itemH, shrink; + if ( this->Orientation == VTK_ORIENT_VERTICAL ) { + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + double delimeter=0.0; + if(GetDistributionVisibility() && distrVisibility) { + delimeter=0.01*size[0]; //1 % from horizontal size of the full presentation size. + barWidth = size[0] - 4 - labelSize[0]; + distrHeight = barWidth/2; + } else { + barWidth = size[0] - 4 - labelSize[0]; + distrHeight = 0; + } + + barHeight = (int)(0.86*size[1]); + delta=(double)barHeight/numColors; + + for ( i=0; iSetPoint(2*i,x); + x[0] = barWidth; + pts->SetPoint(2*i+1,x); + } + + if(GetDistributionVisibility() && distrVisibility) { + // Distribution points + shrink = delta*SHRINK_COEF; + vtkIdType distPtsId=0; + vtkIdType distPtsIds[4]; + for(i=0; iSetPoint(distPtsId++,x); + + // second point of polygon (quadrangle) + x[0] = itemH; + distPtsIds[1] = distPtsId; + distrPts->SetPoint(distPtsId++,x); + + x[1] = i*delta+delta-shrink; + + // third point of polygon (quadrangle) + x[0] = 0; + distPtsIds[3] = distPtsId; + distrPts->SetPoint(distPtsId++,x); + + // fourth point of polygon (quadrangle) + x[0] = itemH; + distPtsIds[2] = distPtsId; + distrPts->SetPoint(distPtsId++,x); + + //Inser Quadrangle + distrPolys->InsertNextCell(4,distPtsIds); + } + } + } + } + // rnv end + else { + barWidth = size[0]; + + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + double coef1, delimeter=0.0; + if(GetDistributionVisibility() && distrVisibility) { + coef1=0.62; + distrHeight = (int)((coef1/2)*size[1]); + //delimeter between distribution diagram and scalar bar + delimeter=0.02*size[1]; + } + else { + coef1=0.4; + barHeight = (int)(coef1*size[1]); + distrHeight = 0; + } + + barHeight = (int)(coef1*size[1]); + + delta=(double)barWidth/numColors; + for (i=0; iSetPoint(2*i,x); + x[1] = distrHeight + delimeter; + pts->SetPoint(2*i+1,x); + } + + if(GetDistributionVisibility() && distrVisibility) { + // Distribution points + shrink = delta*SHRINK_COEF; + vtkIdType distPtsId=0; + vtkIdType distPtsIds[4]; + for(i=0; iSetPoint(distPtsId++,x); + + // second point of polygon (quadrangle) + x[0] = i*delta+shrink; + x[1] = itemH; + distPtsIds[3] = distPtsId; + distrPts->SetPoint(distPtsId++,x); + + // third point of polygon (quadrangle) + x[0] = i*delta+delta-shrink; + x[1] = 0; + distPtsIds[1] = distPtsId; + distrPts->SetPoint(distPtsId++,x); + + // fourth point of polygon (quadrangle) + x[0] = i*delta+delta-shrink; + x[1] = itemH; + distPtsIds[2] = distPtsId; + distrPts->SetPoint(distPtsId++,x); + + // Add polygon into poly data + distrPolys->InsertNextCell(4,distPtsIds); + } + } + } + // rnv end + } + + //polygons & cell colors + unsigned char *rgba, *rgb; + vtkIdType ptIds[4], dcCount=0; + for (i=0; iInsertNextCell(4,ptIds); + + if ( isLogTable ) + { + double rgbval = log10(range[0]) + + i*(log10(range[1])-log10(range[0]))/(numColors -1); + rgba = lut->MapValue(pow(10.0,rgbval)); + } + else + { + rgba = lut->MapValue(range[0] + (range[1] - range[0])* + ((double)i /(numColors-1.0))); + } + + rgb = colors->GetPointer(3*i); //write into array directly + rgb[0] = rgba[0]; + rgb[1] = rgba[1]; + rgb[2] = rgba[2]; + + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + if(myNbValues[i] && myDistributionColoringType == SMESH_MULTICOLOR_TYPE && GetDistributionVisibility() && distrVisibility) + { + rgb = distColors->GetPointer(3*dcCount); //write into array directly + rgb[0] = rgba[0]; + rgb[1] = rgba[1]; + rgb[2] = rgba[2]; + dcCount++; + } + } + + // Now position everything properly + // + double val; + if (this->Orientation == VTK_ORIENT_VERTICAL) + { + int sizeTextData[2]; + + // center the title + this->TitleActor->SetPosition(size[0]/2, 0.9*size[1]); + + for (i=0; i < this->NumberOfLabels; i++) + { + if (this->NumberOfLabels > 1) + { + val = (double)i/(this->NumberOfLabels-1) *barHeight; + } + else + { + val = 0.5*barHeight; + } + this->TextMappers[i]->GetSize(viewport,sizeTextData); + this->TextMappers[i]->GetTextProperty()->SetJustificationToLeft(); + this->TextActors[i]->SetPosition(barWidth+3, + val - sizeTextData[1]/2); + } + } + else + { + this->TitleActor->SetPosition(size[0]/2, + barHeight + labelSize[1] + 0.1*size[1]); + for (i=0; i < this->NumberOfLabels; i++) + { + this->TextMappers[i]->GetTextProperty()->SetJustificationToCentered(); + if (this->NumberOfLabels > 1) + { + val = (double)i/(this->NumberOfLabels-1) * barWidth; + } + else + { + val = 0.5*barWidth; + } + this->TextActors[i]->SetPosition(val, barHeight + 0.05*size[1]); + } + } + + this->BuildTime.Modified(); + } + + // Everything is built, just have to render + if (this->Title != NULL) + { + renderedSomething += this->TitleActor->RenderOpaqueGeometry(viewport); + } + this->ScalarBarActor->RenderOpaqueGeometry(viewport); + this->myDistributionActor->RenderOpaqueGeometry(viewport); + for (i=0; iNumberOfLabels; i++) + { + renderedSomething += this->TextActors[i]->RenderOpaqueGeometry(viewport); + } + + renderedSomething = (renderedSomething > 0)?(1):(0); + + return renderedSomething; +} + +//---------------------------------------------------------------------------- +void SMESH_ScalarBarActor::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + + if ( this->LookupTable ) + { + os << indent << "Lookup Table:\n"; + this->LookupTable->PrintSelf(os,indent.GetNextIndent()); + } + else + { + os << indent << "Lookup Table: (none)\n"; + } + + if (this->TitleTextProperty) + { + os << indent << "Title Text Property:\n"; + this->TitleTextProperty->PrintSelf(os,indent.GetNextIndent()); + } + else + { + os << indent << "Title Text Property: (none)\n"; + } + + if (this->LabelTextProperty) + { + os << indent << "Label Text Property:\n"; + this->LabelTextProperty->PrintSelf(os,indent.GetNextIndent()); + } + else + { + os << indent << "Label Text Property: (none)\n"; + } + + os << indent << "Title: " << (this->Title ? this->Title : "(none)") << "\n"; + os << indent << "Maximum Number Of Colors: " + << this->MaximumNumberOfColors << "\n"; + os << indent << "Number Of Labels: " << this->NumberOfLabels << "\n"; + os << indent << "Number Of Labels Built: " << this->NumberOfLabelsBuilt << "\n"; + + os << indent << "Orientation: "; + if ( this->Orientation == VTK_ORIENT_HORIZONTAL ) + { + os << "Horizontal\n"; + } + else + { + os << "Vertical\n"; + } + + os << indent << "Label Format: " << this->LabelFormat << "\n"; +} + +//---------------------------------------------------------------------------- +void SMESH_ScalarBarActor::ShallowCopy(vtkProp *prop) +{ + SMESH_ScalarBarActor *a = SMESH_ScalarBarActor::SafeDownCast(prop); + if ( a != NULL ) + { + this->SetPosition2(a->GetPosition2()); + this->SetLookupTable(a->GetLookupTable()); + this->SetMaximumNumberOfColors(a->GetMaximumNumberOfColors()); + this->SetOrientation(a->GetOrientation()); + this->SetLabelTextProperty(a->GetLabelTextProperty()); + this->SetTitleTextProperty(a->GetTitleTextProperty()); + this->SetLabelFormat(a->GetLabelFormat()); + this->SetTitle(a->GetTitle()); + this->GetPositionCoordinate()->SetCoordinateSystem( + a->GetPositionCoordinate()->GetCoordinateSystem()); + this->GetPositionCoordinate()->SetValue( + a->GetPositionCoordinate()->GetValue()); + this->GetPosition2Coordinate()->SetCoordinateSystem( + a->GetPosition2Coordinate()->GetCoordinateSystem()); + this->GetPosition2Coordinate()->SetValue( + a->GetPosition2Coordinate()->GetValue()); + } + + // Now do superclass + this->vtkActor2D::ShallowCopy(prop); +} + +//---------------------------------------------------------------------------- +void SMESH_ScalarBarActor::AllocateAndSizeLabels(int *labelSize, + int *size, + vtkViewport *viewport, + double *range) +{ + labelSize[0] = labelSize[1] = 0; + + this->TextMappers = new vtkTextMapper * [this->NumberOfLabels]; + this->TextActors = new vtkActor2D * [this->NumberOfLabels]; + + char string[512]; + + double val; + int i; + + // TODO: this should be optimized, maybe by keeping a list of + // allocated mappers, in order to avoid creation/destruction of + // their underlying text properties (i.e. each time a mapper is + // created, text properties are created and shallow-assigned a font size + // which value might be "far" from the target font size). + + // is this a vtkLookupTable or a subclass of vtkLookupTable + // with its scale set to log + vtkLookupTable *LUT = vtkLookupTable::SafeDownCast( this->LookupTable ); + int isLogTable = 0; + if ( LUT ) + { + if ( LUT->GetScale() == VTK_SCALE_LOG10 ) + { + isLogTable = 1; + } + } + + for (i=0; i < this->NumberOfLabels; i++) + { + this->TextMappers[i] = vtkTextMapper::New(); + + if ( isLogTable ) + { + double lval; + if (this->NumberOfLabels > 1) + { + lval = log10(range[0]) + (double)i/(this->NumberOfLabels-1) * + (log10(range[1])-log10(range[0])); + } + else + { + lval = log10(range[0]) + 0.5*(log10(range[1])-log10(range[0])); + } + val = pow(10.0,lval); + } + else + { + if (this->NumberOfLabels > 1) + { + val = range[0] + + (double)i/(this->NumberOfLabels-1) * (range[1]-range[0]); + } + else + { + val = range[0] + 0.5*(range[1]-range[0]); + } + } + + sprintf(string, this->LabelFormat, val); + this->TextMappers[i]->SetInput(string); + + // Shallow copy here so that the size of the label prop is not affected + // by the automatic adjustment of its text mapper's size (i.e. its + // mapper's text property is identical except for the font size + // which will be modified later). This allows text actors to + // share the same text property, and in that case specifically allows + // the title and label text prop to be the same. + this->TextMappers[i]->GetTextProperty()->ShallowCopy( + this->LabelTextProperty); + + this->TextActors[i] = vtkActor2D::New(); + this->TextActors[i]->SetMapper(this->TextMappers[i]); + this->TextActors[i]->SetProperty(this->GetProperty()); + this->TextActors[i]->GetPositionCoordinate()-> + SetReferenceCoordinate(this->PositionCoordinate); + } + + if (this->NumberOfLabels) + { + int targetWidth, targetHeight; + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + bool distrVisibility = this->MaximumNumberOfColors == this->myNbValues.size(); + double coef; + if( GetDistributionVisibility() && distrVisibility ) + if(this->Orientation == VTK_ORIENT_VERTICAL) + coef = 0.4; + else + coef = 0.18; + else + if(this->Orientation == VTK_ORIENT_VERTICAL) + coef = 0.6; + else + coef=0.25; + + + if ( this->Orientation == VTK_ORIENT_VERTICAL ) + { + targetWidth = (int)(coef*size[0]); + targetHeight = (int)(0.86*size[1]/this->NumberOfLabels); + } + else + { + targetWidth = (int)(size[0]*0.8/this->NumberOfLabels); + targetHeight = (int)(coef*size[1]); + } + // rnv end + + vtkTextMapper::SetMultipleConstrainedFontSize(viewport, + targetWidth, + targetHeight, + this->TextMappers, + this->NumberOfLabels, + labelSize); + } +} + +//---------------------------------------------------------------------------- +void SMESH_ScalarBarActor::SizeTitle(int *titleSize, + int *size, + vtkViewport *viewport) +{ + titleSize[0] = titleSize[1] = 0; + + if (this->Title == NULL || !strlen(this->Title)) + { + return; + } + + int targetWidth, targetHeight; + + targetWidth = size[0]; + // rnv begin + // Customization of the vtkScalarBarActor to show distribution histogram. + bool distrVisibility = this->MaximumNumberOfColors == this->myNbValues.size(); + double coef; + if( GetDistributionVisibility() && distrVisibility ) + coef=0.18; + else + coef=0.25; + + if ( this->Orientation == VTK_ORIENT_VERTICAL ) + { + targetHeight = (int)(0.1*size[1]); + } + else + { + targetHeight = (int)(coef*size[1]); + } + + this->TitleMapper->SetConstrainedFontSize( + viewport, targetWidth, targetHeight); + + this->TitleMapper->GetSize(viewport, titleSize); +} + + +/*--------------------------------------------------------------------------*/ +void SMESH_ScalarBarActor::SetDistributionVisibility(int flag) { + myDistributionActor->SetVisibility(flag); + Modified(); +} + + +/*--------------------------------------------------------------------------*/ +int SMESH_ScalarBarActor::GetDistributionVisibility() { + return myDistributionActor->GetVisibility(); +} + + +void SMESH_ScalarBarActor::SetDistribution(std::vector theNbValues) { + myNbValues = theNbValues; +} + + +void SMESH_ScalarBarActor::SetDistributionColor (double rgb[3]) { + myDistributionActor->GetProperty()->SetColor(rgb); + Modified(); +} + +void SMESH_ScalarBarActor::GetDistributionColor (double rgb[3]) { + myDistributionActor->GetProperty()->GetColor(rgb); +} diff --git a/src/OBJECT/SMESH_ScalarBarActor.h b/src/OBJECT/SMESH_ScalarBarActor.h new file mode 100644 index 000000000..0f895cd57 --- /dev/null +++ b/src/OBJECT/SMESH_ScalarBarActor.h @@ -0,0 +1,246 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SCALAR BAR : 2D Actor for the visualization scalar bar with the distribution diagram +// it is customized vtkScalarBarActor. +// File : SMESH_ScalarBarActor.h +// Author : Roman NIKOLAEV +// Module : SMESH + + +// .NAME vtkScalarBarActor - Create a scalar bar with labels +// .SECTION Description +// vtkScalarBarActor creates a scalar bar with annotation text. A scalar +// bar is a legend that indicates to the viewer the correspondence between +// color value and data value. The legend consists of a rectangular bar +// made of rectangular pieces each colored a constant value. Since +// vtkScalarBarActor is a subclass of vtkActor2D, it is drawn in the image +// plane (i.e., in the renderer's viewport) on top of the 3D graphics window. +// +// To use vtkScalarBarActor you must associate a vtkScalarsToColors (or +// subclass) with it. The lookup table defines the colors and the +// range of scalar values used to map scalar data. Typically, the +// number of colors shown in the scalar bar is not equal to the number +// of colors in the lookup table, in which case sampling of +// the lookup table is performed. +// +// Other optional capabilities include specifying the fraction of the +// viewport size (both x and y directions) which will control the size +// of the scalar bar and the number of annotation labels. The actual position +// of the scalar bar on the screen is controlled by using the +// vtkActor2D::SetPosition() method (by default the scalar bar is +// centered in the viewport). Other features include the ability to +// orient the scalar bar horizontally of vertically and controlling +// the format (printf style) with which to print the labels on the +// scalar bar. Also, the vtkScalarBarActor's property is applied to +// the scalar bar and annotation (including layer, and +// compositing operator). +// +// Set the text property/attributes of the title and the labels through the +// vtkTextProperty objects associated to this actor. +// +// .SECTION Caveats +// If a vtkLogLookupTable is specified as the lookup table to use, then the +// labels are created using a logarithmic scale. +// +// .SECTION See Also +// vtkActor2D vtkTextProperty vtkTextMapper vtkPolyDataMapper2D + +#ifndef SMESH_SCALAR_BAR_ACTOR_H +#define SMESH_SCALAR_BAR_ACTOR_H + +#include + +#include + +#include + +class vtkPolyData; +class vtkPolyDataMapper2D; +class vtkScalarsToColors; +class vtkTextMapper; +class vtkTextProperty; + +#define VTK_ORIENT_HORIZONTAL 0 +#define VTK_ORIENT_VERTICAL 1 + +#define SMESH_MONOCOLOR_TYPE 0 +#define SMESH_MULTICOLOR_TYPE 1 + + +class SMESHOBJECT_EXPORT SMESH_ScalarBarActor: public vtkActor2D { + public: + void PrintSelf(ostream& os, vtkIndent indent); + + vtkTypeMacro(SMESH_ScalarBarActor,vtkActor2D); + + // Description: + // Instantiate object with 64 maximum colors; 5 labels; %%-#6.3g label + // format, no title, and vertical orientation. The initial scalar bar + // size is (0.05 x 0.8) of the viewport size. + static SMESH_ScalarBarActor *New(); + + // Description: + // Draw the scalar bar and annotation text to the screen. + int RenderOpaqueGeometry(vtkViewport* viewport); + int RenderTranslucentGeometry(vtkViewport*) { return 0; }; + int RenderOverlay(vtkViewport* viewport); + + // Description: + // Release any graphics resources that are being consumed by this actor. + // The parameter window could be used to determine which graphic + // resources to release. + virtual void ReleaseGraphicsResources(vtkWindow *); + + // Description: + // Set/Get the vtkLookupTable to use. The lookup table specifies the number + // of colors to use in the table (if not overridden), as well as the scalar + // range. + virtual void SetLookupTable(vtkScalarsToColors*); + vtkGetObjectMacro(LookupTable,vtkScalarsToColors); + + // Description: + // Set/Get the maximum number of scalar bar segments to show. This may + // differ from the number of colors in the lookup table, in which case + // the colors are samples from the lookup table. + vtkSetClampMacro(MaximumNumberOfColors, int, 2, VTK_LARGE_INTEGER); + vtkGetMacro(MaximumNumberOfColors, int); + + // Description: + // Set/Get the number of annotation labels to show. + vtkSetClampMacro(NumberOfLabels, int, 0, 64); + vtkGetMacro(NumberOfLabels, int); + + // Description: + // Control the orientation of the scalar bar. + vtkSetClampMacro(Orientation,int,VTK_ORIENT_HORIZONTAL, VTK_ORIENT_VERTICAL); + vtkGetMacro(Orientation, int); + void SetOrientationToHorizontal() + {this->SetOrientation(VTK_ORIENT_HORIZONTAL);}; + void SetOrientationToVertical() {this->SetOrientation(VTK_ORIENT_VERTICAL);}; + + // Description: + // Set/Get the title text property. + virtual void SetTitleTextProperty(vtkTextProperty *p); + vtkGetObjectMacro(TitleTextProperty,vtkTextProperty); + + // Description: + // Set/Get the labels text property. + virtual void SetLabelTextProperty(vtkTextProperty *p); + vtkGetObjectMacro(LabelTextProperty,vtkTextProperty); + + // Description: + // Set/Get the format with which to print the labels on the scalar + // bar. + vtkSetStringMacro(LabelFormat); + vtkGetStringMacro(LabelFormat); + + // Description: + // Set/Get the title of the scalar bar actor, + vtkSetStringMacro(Title); + vtkGetStringMacro(Title); + + // Description: + // Shallow copy of a scalar bar actor. Overloads the virtual vtkProp method. + void ShallowCopy(vtkProp *prop); + + // Description: + // Set visibility of the distribution histogram + // rnv: Customization of the vtkScalarBarActor to show distribution histogram: + virtual void SetDistributionVisibility(int flag); + + // Description: + // Set visibility of the distribution histogram + // rnv: Customization of the vtkScalarBarActor to show distribution histogram: + virtual int GetDistributionVisibility(); + // Description: + // Set distribution + virtual void SetDistribution(std::vector theNbValues); + + // Description: + // Set distribution coloring type (SMESH_MONOCOLOR_TYPE or SMESH_MULTICOLOR_TYPE) + void SetDistributionColoringType(int theDistributionColoringType) {myDistributionColoringType = theDistributionColoringType;Modified();} + + // Description: + // Get distribution coloring type ((SMESH_MONOCOLOR_TYPE or SMESH_MULTICOLOR_TYPE)) + int GetDistributionColoringType() {return myDistributionColoringType;} + + // Description: + // Set Distribution Color + void SetDistributionColor (double rgb[3]); + + // Description: + // Get Distribution Color + void GetDistributionColor (double rgb[3]); + + + + protected: + SMESH_ScalarBarActor(); + ~SMESH_ScalarBarActor(); + + vtkScalarsToColors *LookupTable; + vtkTextProperty *TitleTextProperty; + vtkTextProperty *LabelTextProperty; + + int MaximumNumberOfColors; + int NumberOfLabels; + int NumberOfLabelsBuilt; + int Orientation; + char *Title; + char *LabelFormat; + + vtkTextMapper **TextMappers; + virtual void AllocateAndSizeLabels(int *labelSize, int *size, + vtkViewport *viewport, double *range); + + + + private: + vtkTextMapper *TitleMapper; + vtkActor2D *TitleActor; + + vtkActor2D **TextActors; + + vtkPolyData *ScalarBar; + vtkPolyDataMapper2D *ScalarBarMapper; + vtkActor2D *ScalarBarActor; + + vtkTimeStamp BuildTime; + int LastSize[2]; + int LastOrigin[2]; + + void SizeTitle(int *titleSize, int *size, vtkViewport *viewport); + + // rnv: Customization of the vtkScalarBarActor to show distribution histogram: + vtkPolyData* myDistribution; //Distribution polygonal data + vtkActor2D* myDistributionActor; //Distribution actor + vtkPolyDataMapper2D* myDistributionMapper; //Distribution mapper + std::vector myNbValues; //Nb values for the range + int myDistributionColoringType; //Distribution color type (monocolor or multicolor) + + private: + SMESH_ScalarBarActor(const SMESH_ScalarBarActor&); // Not implemented. + void operator=(const SMESH_ScalarBarActor&); // Not implemented. +}; + +#endif //SMESH_SCALAR_BAR_ACTOR_H diff --git a/src/PluginUtils/GeomSelectionTools.cxx b/src/PluginUtils/GeomSelectionTools.cxx index ceafd175d..45d5c42a3 100644 --- a/src/PluginUtils/GeomSelectionTools.cxx +++ b/src/PluginUtils/GeomSelectionTools.cxx @@ -297,5 +297,47 @@ GeomAbs_SurfaceType GeomSelectionTools::getFaceInformation(TopoDS_Shape S) } +////////////////////////////////////////// +// Utility functions +////////////////////////////////////////// +#include +#include +QString PluginUtils::PrintDoubleValue( double theValue, int thePrecision ) +{ + const double prec = 1e-12; + + if ( qAbs(theValue) < prec ) + return "0"; + + QString aRes = QLocale().toString( theValue, thePrecision >= 0 ? 'f' : 'g', qAbs( thePrecision ) ); + + if ( prec > 0 ) { + int p = 0; + while ( p < thePrecision ) { + QString aRes = QLocale().toString( theValue, thePrecision >= 0 ? 'f' : 'g', qAbs( p++ ) ); + double v = aRes.toDouble(); + double err = qAbs( theValue - v ); + if ( err > 0 && err <= prec ) + break; + } + } + + // remove trailing zeroes + + QRegExp expre( QString( "(%1|%2)[+-]?[0-9]+$" ).arg( QLocale().exponential().toLower(), + QLocale().exponential().toUpper() ) ); + + int idx = aRes.indexOf( expre ); + QString aResExp = ""; + if ( idx >= 0 ) { + aResExp = aRes.mid( idx ); + aRes = aRes.left( idx ); + } + + if ( aRes.contains( QLocale().decimalPoint() ) ) + aRes.remove( QRegExp( QString( "(\\%1|0)0*$" ).arg( QLocale().decimalPoint() ) ) ); + + return aRes == "-0" ? QString( "0" ) : aRes + aResExp; +} diff --git a/src/PluginUtils/GeomSelectionTools.h b/src/PluginUtils/GeomSelectionTools.h index 0995556f1..d00a2ba22 100644 --- a/src/PluginUtils/GeomSelectionTools.h +++ b/src/PluginUtils/GeomSelectionTools.h @@ -78,6 +78,14 @@ public: _PTR(Study) getMyStudy(); }; +////////////////////////////////////////// +// Utility functions +////////////////////////////////////////// + +namespace PluginUtils +{ + GEOMSELECTIONTOOLS_EXPORT QString PrintDoubleValue( double, int = 16 ); +}; #endif // _GEOMSELECTIONTOOLS_H_ diff --git a/src/SMDS/SMDS_Mesh.cxx b/src/SMDS/SMDS_Mesh.cxx index 408ad1f0e..d3d41b135 100644 --- a/src/SMDS/SMDS_Mesh.cxx +++ b/src/SMDS/SMDS_Mesh.cxx @@ -2191,12 +2191,18 @@ namespace { class IdSortedIterator : public SMDS_Iterator { const SMDS_MeshElementIDFactory& myIDFact; - int myID, myMaxID; + int myID, myMaxID, myNbFound, myTotalNb; + SMDSAbs_ElementType myType; ELEM myElem; public: - IdSortedIterator(const SMDS_MeshElementIDFactory& fact) - :myIDFact( fact ), myID(1), myMaxID( myIDFact.GetMaxID() ), myElem(0) + IdSortedIterator(const SMDS_MeshElementIDFactory& fact, + const SMDSAbs_ElementType type, // SMDSAbs_All NOT allowed!!! + const int totalNb) + :myIDFact( fact ), + myID(1), myMaxID( myIDFact.GetMaxID() ),myNbFound(0), myTotalNb( totalNb ), + myType( type ), + myElem(0) { next(); } @@ -2207,8 +2213,14 @@ namespace { ELEM next() { ELEM current = myElem; - for ( myElem = 0; myID <= myMaxID && !myElem; ++myID ) - myElem = (ELEM) myIDFact.MeshElement( myID ); + + for ( myElem = 0; !myElem && myNbFound < myTotalNb && myID <= myMaxID; ++myID ) + if ((myElem = (ELEM) myIDFact.MeshElement( myID )) + && myElem->GetType() != myType ) + myElem = 0; + + myNbFound += bool(myElem); + return current; } }; @@ -2224,7 +2236,7 @@ SMDS_NodeIteratorPtr SMDS_Mesh::nodesIterator(bool idInceasingOrder) const < SetOfNodes, const SMDS_MeshNode*, SMDS_NodeIterator > TIterator; typedef IdSortedIterator< const SMDS_MeshNode* > TSortedIterator; return ( idInceasingOrder ? - SMDS_NodeIteratorPtr( new TSortedIterator( *myNodeIDFactory )) : + SMDS_NodeIteratorPtr( new TSortedIterator( *myNodeIDFactory, SMDSAbs_Node, NbNodes())) : SMDS_NodeIteratorPtr( new TIterator(myNodes))); } @@ -2232,44 +2244,64 @@ SMDS_NodeIteratorPtr SMDS_Mesh::nodesIterator(bool idInceasingOrder) const ///Return an iterator on 0D elements of the current mesh. /////////////////////////////////////////////////////////////////////////////// -SMDS_0DElementIteratorPtr SMDS_Mesh::elements0dIterator() const +SMDS_0DElementIteratorPtr SMDS_Mesh::elements0dIterator(bool idInceasingOrder) const { typedef MYNCollection_Map_Iterator < SetOf0DElements, const SMDS_Mesh0DElement*, SMDS_0DElementIterator > TIterator; - return SMDS_0DElementIteratorPtr(new TIterator(my0DElements)); + typedef IdSortedIterator< const SMDS_Mesh0DElement* > TSortedIterator; + return ( idInceasingOrder ? + SMDS_0DElementIteratorPtr( new TSortedIterator( *myElementIDFactory, + SMDSAbs_0DElement, + Nb0DElements() )) : + SMDS_0DElementIteratorPtr( new TIterator(my0DElements))); } /////////////////////////////////////////////////////////////////////////////// ///Return an iterator on edges of the current mesh. /////////////////////////////////////////////////////////////////////////////// -SMDS_EdgeIteratorPtr SMDS_Mesh::edgesIterator() const +SMDS_EdgeIteratorPtr SMDS_Mesh::edgesIterator(bool idInceasingOrder) const { typedef MYNCollection_Map_Iterator < SetOfEdges, const SMDS_MeshEdge*, SMDS_EdgeIterator > TIterator; - return SMDS_EdgeIteratorPtr(new TIterator(myEdges)); + typedef IdSortedIterator< const SMDS_MeshEdge* > TSortedIterator; + return ( idInceasingOrder ? + SMDS_EdgeIteratorPtr( new TSortedIterator( *myElementIDFactory, + SMDSAbs_Edge, + NbEdges() )) : + SMDS_EdgeIteratorPtr(new TIterator(myEdges))); } /////////////////////////////////////////////////////////////////////////////// ///Return an iterator on faces of the current mesh. /////////////////////////////////////////////////////////////////////////////// -SMDS_FaceIteratorPtr SMDS_Mesh::facesIterator() const +SMDS_FaceIteratorPtr SMDS_Mesh::facesIterator(bool idInceasingOrder) const { typedef MYNCollection_Map_Iterator < SetOfFaces, const SMDS_MeshFace*, SMDS_FaceIterator > TIterator; - return SMDS_FaceIteratorPtr(new TIterator(myFaces)); + typedef IdSortedIterator< const SMDS_MeshFace* > TSortedIterator; + return ( idInceasingOrder ? + SMDS_FaceIteratorPtr( new TSortedIterator( *myElementIDFactory, + SMDSAbs_Face, + NbFaces() )) : + SMDS_FaceIteratorPtr(new TIterator(myFaces))); } /////////////////////////////////////////////////////////////////////////////// ///Return an iterator on volumes of the current mesh. /////////////////////////////////////////////////////////////////////////////// -SMDS_VolumeIteratorPtr SMDS_Mesh::volumesIterator() const +SMDS_VolumeIteratorPtr SMDS_Mesh::volumesIterator(bool idInceasingOrder) const { typedef MYNCollection_Map_Iterator < SetOfVolumes, const SMDS_MeshVolume*, SMDS_VolumeIterator > TIterator; - return SMDS_VolumeIteratorPtr(new TIterator(myVolumes)); + typedef IdSortedIterator< const SMDS_MeshVolume* > TSortedIterator; + return ( idInceasingOrder ? + SMDS_VolumeIteratorPtr( new TSortedIterator( *myElementIDFactory, + SMDSAbs_Volume, + NbVolumes() )) : + SMDS_VolumeIteratorPtr(new TIterator(myVolumes))); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/SMDS/SMDS_Mesh.hxx b/src/SMDS/SMDS_Mesh.hxx index 36f7e37c1..e9397b6a2 100644 --- a/src/SMDS/SMDS_Mesh.hxx +++ b/src/SMDS/SMDS_Mesh.hxx @@ -48,11 +48,11 @@ public: SMDS_Mesh(); - SMDS_NodeIteratorPtr nodesIterator(bool idInceasingOrder=false) const; - SMDS_0DElementIteratorPtr elements0dIterator() const; - SMDS_EdgeIteratorPtr edgesIterator() const; - SMDS_FaceIteratorPtr facesIterator() const; - SMDS_VolumeIteratorPtr volumesIterator() const; + SMDS_NodeIteratorPtr nodesIterator (bool idInceasingOrder=false) const; + SMDS_0DElementIteratorPtr elements0dIterator(bool idInceasingOrder=false) const; + SMDS_EdgeIteratorPtr edgesIterator (bool idInceasingOrder=false) const; + SMDS_FaceIteratorPtr facesIterator (bool idInceasingOrder=false) const; + SMDS_VolumeIteratorPtr volumesIterator (bool idInceasingOrder=false) const; SMDS_ElemIteratorPtr elementsIterator(SMDSAbs_ElementType type=SMDSAbs_All) const; SMDSAbs_ElementType GetElementType( const int id, const bool iselem ) const; diff --git a/src/SMDS/SMDS_MeshElement.hxx b/src/SMDS/SMDS_MeshElement.hxx index 938abf0b2..593b7fe00 100644 --- a/src/SMDS/SMDS_MeshElement.hxx +++ b/src/SMDS/SMDS_MeshElement.hxx @@ -69,7 +69,7 @@ public: ///Return the type of the current element virtual SMDSAbs_ElementType GetType() const = 0; - virtual bool IsPoly() const { return false; }; + virtual bool IsPoly() const { return false; } virtual bool IsQuadratic() const; //! Return type of entity virtual SMDSAbs_EntityType GetEntityType() const = 0; diff --git a/src/SMDS/SMDS_MeshNode.cxx b/src/SMDS/SMDS_MeshNode.cxx index 73610b661..9df6348a5 100644 --- a/src/SMDS/SMDS_MeshNode.cxx +++ b/src/SMDS/SMDS_MeshNode.cxx @@ -239,11 +239,6 @@ void SMDS_MeshNode::ClearInverseElements() myInverseElements.Clear(); } -bool SMDS_MeshNode::emptyInverseElements() -{ - return myInverseElements.IsEmpty() != Standard_False; -} - //================================================================================ /*! * \brief Count inverse elements of given type diff --git a/src/SMDS/SMDS_MeshNode.hxx b/src/SMDS/SMDS_MeshNode.hxx index 2d932f355..9ab02f20f 100644 --- a/src/SMDS/SMDS_MeshNode.hxx +++ b/src/SMDS/SMDS_MeshNode.hxx @@ -38,23 +38,26 @@ class SMDS_EXPORT SMDS_MeshNode:public SMDS_MeshElement public: SMDS_MeshNode(double x, double y, double z); - void Print(std::ostream & OS) const; + double X() const; double Y() const; double Z() const; + void setXYZ(double x, double y, double z); + void AddInverseElement(const SMDS_MeshElement * ME); void RemoveInverseElement(const SMDS_MeshElement * parent); void ClearInverseElements(); - bool emptyInverseElements(); SMDS_ElemIteratorPtr GetInverseElementIterator(SMDSAbs_ElementType type=SMDSAbs_All) const; int NbInverseElements(SMDSAbs_ElementType type=SMDSAbs_All) const; + void SetPosition(const SMDS_PositionPtr& aPos); const SMDS_PositionPtr& GetPosition() const; + SMDSAbs_ElementType GetType() const; SMDSAbs_EntityType GetEntityType() const {return SMDSEntity_Node;} - int NbNodes() const; - void setXYZ(double x, double y, double z); + friend bool operator<(const SMDS_MeshNode& e1, const SMDS_MeshNode& e2); + void Print(std::ostream & OS) const; /*! * \brief Return node by its index @@ -62,6 +65,7 @@ public: * \retval const SMDS_MeshNode* - the node */ virtual const SMDS_MeshNode* GetNode(const int) const { return this; } + virtual int NbNodes() const; protected: SMDS_ElemIteratorPtr diff --git a/src/SMDS/SMDS_VolumeTool.cxx b/src/SMDS/SMDS_VolumeTool.cxx index 52633d610..42640287c 100644 --- a/src/SMDS/SMDS_VolumeTool.cxx +++ b/src/SMDS/SMDS_VolumeTool.cxx @@ -518,8 +518,10 @@ bool SMDS_VolumeTool::Set (const SMDS_MeshElement* theVolume) // define volume orientation XYZ botNormal; GetFaceNormal( 0, botNormal.x, botNormal.y, botNormal.z ); - const SMDS_MeshNode* topNode = myVolumeNodes[ myVolumeNbNodes - 1 ]; const SMDS_MeshNode* botNode = myVolumeNodes[ 0 ]; + int topNodeIndex = myVolume->NbCornerNodes() - 1; + while ( !IsLinked( 0, topNodeIndex, /*ignoreMediumNodes=*/true )) --topNodeIndex; + const SMDS_MeshNode* topNode = myVolumeNodes[ topNodeIndex ]; XYZ upDir (topNode->X() - botNode->X(), topNode->Y() - botNode->Y(), topNode->Z() - botNode->Z() ); @@ -1024,6 +1026,27 @@ bool SMDS_VolumeTool::GetFaceNormal (int faceIndex, double & X, double & Y, doub return true; } +//================================================================================ +/*! + * \brief Return barycenter of a face + */ +//================================================================================ + +bool SMDS_VolumeTool::GetFaceBaryCenter (int faceIndex, double & X, double & Y, double & Z) +{ + if ( !setFace( faceIndex )) + return false; + + X = Y = Z = 0.0; + for ( int i = 0; i < myFaceNbNodes; ++i ) + { + X += myFaceNodes[i]->X() / myFaceNbNodes; + Y += myFaceNodes[i]->Y() / myFaceNbNodes; + Z += myFaceNodes[i]->Z() / myFaceNbNodes; + } + return true; +} + //======================================================================= //function : GetFaceArea //purpose : Return face area @@ -1085,10 +1108,12 @@ int SMDS_VolumeTool::GetOppFaceIndex( int faceIndex ) const //======================================================================= //function : IsLinked //purpose : return true if theNode1 is linked with theNode2 +// If theIgnoreMediumNodes then corner nodes of quadratic cell are considered linked as well //======================================================================= bool SMDS_VolumeTool::IsLinked (const SMDS_MeshNode* theNode1, - const SMDS_MeshNode* theNode2) const + const SMDS_MeshNode* theNode2, + const bool theIgnoreMediumNodes) const { if ( !myVolume ) return false; @@ -1135,10 +1160,12 @@ bool SMDS_VolumeTool::IsLinked (const SMDS_MeshNode* theNode1, //function : IsLinked //purpose : return true if the node with theNode1Index is linked // with the node with theNode2Index +// If theIgnoreMediumNodes then corner nodes of quadratic cell are considered linked as well //======================================================================= bool SMDS_VolumeTool::IsLinked (const int theNode1Index, - const int theNode2Index) const + const int theNode2Index, + bool theIgnoreMediumNodes) const { if ( myVolume->IsPoly() ) { return IsLinked(myVolumeNodes[theNode1Index], myVolumeNodes[theNode2Index]); @@ -1150,10 +1177,31 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, if ( minInd < 0 || maxInd > myVolumeNbNodes - 1 || maxInd == minInd ) return false; - switch ( myVolumeNbNodes ) { - case 4: + SMDSAbs_EntityType type = myVolume->GetEntityType(); + if ( myVolume->IsQuadratic() ) + { + int firstMediumInd = myVolume->NbCornerNodes(); + if ( minInd >= firstMediumInd ) + return false; // medium nodes are not linked + if ( maxInd < firstMediumInd ) // both nodes are corners + if ( theIgnoreMediumNodes ) + type = SMDSAbs_EntityType( int(type)-1 ); // check linkage of corner nodes + else + return false; // corner nodes are not linked directly in a quadratic cell + } + + switch ( type ) { + case SMDSEntity_Tetra: return true; - case 5: + case SMDSEntity_Hexa: + switch ( maxInd - minInd ) { + case 1: return minInd != 3; + case 3: return minInd == 0 || minInd == 4; + case 4: return true; + default:; + } + break; + case SMDSEntity_Pyramid: if ( maxInd == 4 ) return true; switch ( maxInd - minInd ) { @@ -1162,7 +1210,7 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, default:; } break; - case 6: + case SMDSEntity_Penta: switch ( maxInd - minInd ) { case 1: return minInd != 2; case 2: return minInd == 0 || minInd == 3; @@ -1170,15 +1218,7 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, default:; } break; - case 8: - switch ( maxInd - minInd ) { - case 1: return minInd != 3; - case 3: return minInd == 0 || minInd == 4; - case 4: return true; - default:; - } - break; - case 10: + case SMDSEntity_Quad_Tetra: { switch ( minInd ) { case 0: if( maxInd==4 || maxInd==6 || maxInd==7 ) return true; @@ -1189,7 +1229,22 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, } break; } - case 13: + case SMDSEntity_Quad_Hexa: + { + switch ( minInd ) { + case 0: if( maxInd==8 || maxInd==11 || maxInd==16 ) return true; + case 1: if( maxInd==8 || maxInd==9 || maxInd==17 ) return true; + case 2: if( maxInd==9 || maxInd==10 || maxInd==18 ) return true; + case 3: if( maxInd==10 || maxInd==11 || maxInd==19 ) return true; + case 4: if( maxInd==12 || maxInd==15 || maxInd==16 ) return true; + case 5: if( maxInd==12 || maxInd==13 || maxInd==17 ) return true; + case 6: if( maxInd==13 || maxInd==14 || maxInd==18 ) return true; + case 7: if( maxInd==14 || maxInd==15 || maxInd==19 ) return true; + default:; + } + break; + } + case SMDSEntity_Quad_Pyramid: { switch ( minInd ) { case 0: if( maxInd==5 || maxInd==8 || maxInd==9 ) return true; @@ -1201,7 +1256,7 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, } break; } - case 15: + case SMDSEntity_Quad_Penta: { switch ( minInd ) { case 0: if( maxInd==6 || maxInd==8 || maxInd==12 ) return true; @@ -1214,21 +1269,6 @@ bool SMDS_VolumeTool::IsLinked (const int theNode1Index, } break; } - case 20: - { - switch ( minInd ) { - case 0: if( maxInd==8 || maxInd==11 || maxInd==16 ) return true; - case 1: if( maxInd==8 || maxInd==9 || maxInd==17 ) return true; - case 2: if( maxInd==9 || maxInd==10 || maxInd==18 ) return true; - case 3: if( maxInd==10 || maxInd==11 || maxInd==19 ) return true; - case 4: if( maxInd==12 || maxInd==15 || maxInd==16 ) return true; - case 5: if( maxInd==12 || maxInd==13 || maxInd==17 ) return true; - case 6: if( maxInd==13 || maxInd==14 || maxInd==18 ) return true; - case 7: if( maxInd==14 || maxInd==15 || maxInd==19 ) return true; - default:; - } - break; - } default:; } return false; diff --git a/src/SMDS/SMDS_VolumeTool.hxx b/src/SMDS/SMDS_VolumeTool.hxx index 6791fb9c7..8d82a6091 100644 --- a/src/SMDS/SMDS_VolumeTool.hxx +++ b/src/SMDS/SMDS_VolumeTool.hxx @@ -102,13 +102,17 @@ class SMDS_EXPORT SMDS_VolumeTool // ----------------------- bool IsLinked (const SMDS_MeshNode* theNode1, - const SMDS_MeshNode* theNode2) const; + const SMDS_MeshNode* theNode2, + const bool theIgnoreMediumNodes=false) const; // Return true if theNode1 is linked with theNode2. + // If theIgnoreMediumNodes then corner nodes of quadratic cell are considered linked as well bool IsLinked (const int theNode1Index, - const int theNode2Index) const; + const int theNode2Index, + bool theIgnoreMediumNodes=false) const; // Return true if the node with theNode1Index is linked // with the node with theNode2Index + // If theIgnoreMediumNodes then corner nodes of quadratic cell are considered linked as well int GetNodeIndex(const SMDS_MeshNode* theNode) const; // Return an index of theNode @@ -158,6 +162,9 @@ class SMDS_EXPORT SMDS_VolumeTool bool GetFaceNormal (int faceIndex, double & X, double & Y, double & Z); // Return a normal to a face + bool GetFaceBaryCenter (int faceIndex, double & X, double & Y, double & Z); + // Return barycenter of a face + double GetFaceArea( int faceIndex ); // Return face area diff --git a/src/SMESH/SMESH_Algo.cxx b/src/SMESH/SMESH_Algo.cxx index 671e2660f..3a6a4efd9 100644 --- a/src/SMESH/SMESH_Algo.cxx +++ b/src/SMESH/SMESH_Algo.cxx @@ -492,7 +492,11 @@ bool SMESH_Algo::InitCompatibleHypoFilter( SMESH_HypoFilter & theFilter, GeomAbs_Shape SMESH_Algo::Continuity(TopoDS_Edge E1, TopoDS_Edge E2) { - E1.Orientation(TopAbs_FORWARD), E2.Orientation(TopAbs_FORWARD); // avoid pb with internal edges + //E1.Orientation(TopAbs_FORWARD), E2.Orientation(TopAbs_FORWARD); // avoid pb with internal edges + if (E1.Orientation() > TopAbs_REVERSED) // INTERNAL + E1.Orientation( TopAbs_FORWARD ); + if (E2.Orientation() > TopAbs_REVERSED) // INTERNAL + E2.Orientation( TopAbs_FORWARD ); TopoDS_Vertex V = TopExp::LastVertex (E1, true); if ( !V.IsSame( TopExp::FirstVertex(E2, true ))) if ( !TopExp::CommonVertex( E1, E2, V )) diff --git a/src/SMESH/SMESH_Algo.hxx b/src/SMESH/SMESH_Algo.hxx index 03c0b7bdb..83b34c3a9 100644 --- a/src/SMESH/SMESH_Algo.hxx +++ b/src/SMESH/SMESH_Algo.hxx @@ -86,14 +86,14 @@ public: /*! * \brief Saves nothing in a stream * \param save - the stream - * \retval virtual std::ostream & - the stream + * \retval std::ostream & - the stream */ virtual std::ostream & SaveTo(std::ostream & save); /*! * \brief Loads nothing from a stream * \param load - the stream - * \retval virtual std::ostream & - the stream + * \retval std::ostream & - the stream */ virtual std::istream & LoadFrom(std::istream & load); @@ -236,7 +236,7 @@ public: * * This method is called when a submesh gets HYP_OK algo_state. * After being set, event listener is notified on each event of a submesh. - * By default non listener is set + * By default none listener is set */ virtual void SetEventListener(SMESH_subMesh* subMesh); @@ -323,7 +323,8 @@ public: */ static std::vector< const SMDS_MeshNode*> GetCommonNodes(const SMDS_MeshElement* e1, const SMDS_MeshElement* e2); -protected: + + protected: /*! * \brief store error and comment and then return ( error == COMPERR_OK ) diff --git a/src/SMESH/SMESH_Block.cxx b/src/SMESH/SMESH_Block.cxx index b26cfbd9a..6d20d6be8 100644 --- a/src/SMESH/SMESH_Block.cxx +++ b/src/SMESH/SMESH_Block.cxx @@ -960,7 +960,7 @@ int SMESH_Block::GetShapeIDByParams ( const gp_XYZ& theCoord ) * \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 theNbVertexInWires - nb of vertices (== nb of edges) in each wire + * \param theNbEdgesInWires - nb of edges (== nb of vertices in closed wire) in each wire * \param theShapeAnalysisAlgo - if true, ShapeAnalysis::OuterWire() is used to find * the outer wire else BRepTools::OuterWire() is used. * \retval int - nb of wires @@ -974,7 +974,7 @@ 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 > & theNbVertexInWires, + list< int > & theNbEdgesInWires, const bool theShapeAnalysisAlgo) { // put wires in a list, so that an outer wire comes first @@ -991,7 +991,7 @@ int SMESH_Block::GetOrderedEdges (const TopoDS_Face& theFace, } // loop on edges of wires - theNbVertexInWires.clear(); + theNbEdgesInWires.clear(); list::iterator wlIt = aWireList.begin(); for ( ; wlIt != aWireList.end(); wlIt++ ) { @@ -1009,7 +1009,7 @@ int SMESH_Block::GetOrderedEdges (const TopoDS_Face& theFace, for ( TopoDS_Iterator e( *wlIt ); e.More(); e.Next(), ++iE ) theEdges.push_back( TopoDS::Edge( e.Value() )); } - theNbVertexInWires.push_back( iE ); + theNbEdgesInWires.push_back( iE ); iE = 0; if ( wlIt == aWireList.begin() && theEdges.size() > 1 ) { // the outer wire // orient closed edges @@ -1047,7 +1047,7 @@ int SMESH_Block::GetOrderedEdges (const TopoDS_Face& theFace, theEdges.splice(theEdges.end(), theEdges, theEdges.begin(), ++theEdges.begin()); TopExp::Vertices( theEdges.front(), vv[0], vv[1], true ); - if ( iE++ > theNbVertexInWires.back() ) { + if ( iE++ > theNbEdgesInWires.back() ) { #ifdef _DEBUG_ gp_Pnt p = BRep_Tool::Pnt( theFirstVertex ); MESSAGE ( " : Warning : vertex "<< theFirstVertex.TShape().operator->() diff --git a/src/SMESH/SMESH_Block.hxx b/src/SMESH/SMESH_Block.hxx index f3d951069..4851c0eaf 100644 --- a/src/SMESH/SMESH_Block.hxx +++ b/src/SMESH/SMESH_Block.hxx @@ -277,7 +277,7 @@ public: static int GetOrderedEdges (const TopoDS_Face& theFace, TopoDS_Vertex theFirstVertex, std::list< TopoDS_Edge >& theEdges, - std::list< int > & theNbVertexInWires, + std::list< int > & theNbEdgesInWires, 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/SMESH/SMESH_Gen.cxx b/src/SMESH/SMESH_Gen.cxx index f2c7f2eef..47947add9 100644 --- a/src/SMESH/SMESH_Gen.cxx +++ b/src/SMESH/SMESH_Gen.cxx @@ -191,7 +191,7 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, } // ------------------------------------------------------------ - // sort list of meshes according to mesh order + // sort list of submeshes according to mesh order // ------------------------------------------------------------ aMesh.SortByMeshOrder( smWithAlgoSupportingSubmeshes ); diff --git a/src/SMESH/SMESH_Group.cxx b/src/SMESH/SMESH_Group.cxx index 4d88aed63..b2f5a125d 100644 --- a/src/SMESH/SMESH_Group.cxx +++ b/src/SMESH/SMESH_Group.cxx @@ -63,5 +63,5 @@ SMESH_Group::SMESH_Group (int theID, SMESH_Group::~SMESH_Group () { - delete myGroupDS; + delete myGroupDS; myGroupDS=0; } diff --git a/src/SMESH/SMESH_Group.hxx b/src/SMESH/SMESH_Group.hxx index 8d942bce4..c3e62ad2a 100644 --- a/src/SMESH/SMESH_Group.hxx +++ b/src/SMESH/SMESH_Group.hxx @@ -24,7 +24,6 @@ // File : SMESH_Group.hxx // Author : Michael Sazonov (OCC) // Module : SMESH -// $Header$ // #ifndef _SMESH_Group_HeaderFile #define _SMESH_Group_HeaderFile diff --git a/src/SMESH/SMESH_HypoFilter.cxx b/src/SMESH/SMESH_HypoFilter.cxx index 1f6685d15..397d8a753 100644 --- a/src/SMESH/SMESH_HypoFilter.cxx +++ b/src/SMESH/SMESH_HypoFilter.cxx @@ -23,13 +23,16 @@ // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_HypoFilter.cxx // Module : SMESH -// $Header$ // #include "SMESH_HypoFilter.hxx" +#include "SMESH_Gen.hxx" #include "SMESH_Hypothesis.hxx" +#include "SMESH_MesherHelper.hxx" #include "SMESH_subMesh.hxx" +#include + using namespace std; @@ -113,7 +116,7 @@ bool SMESH_HypoFilter::InstancePredicate::IsOk(const SMESH_Hypothesis* aHyp, //======================================================================= bool SMESH_HypoFilter::IsAssignedToPredicate::IsOk(const SMESH_Hypothesis* aHyp, - const TopoDS_Shape& aShape) const + const TopoDS_Shape& aShape) const { return ( !_mainShape.IsNull() && !aShape.IsNull() && _mainShape.IsSame( aShape )); } @@ -126,7 +129,19 @@ bool SMESH_HypoFilter::IsAssignedToPredicate::IsOk(const SMESH_Hypothesis* aHyp, bool SMESH_HypoFilter::IsMoreLocalThanPredicate::IsOk(const SMESH_Hypothesis* aHyp, const TopoDS_Shape& aShape) const { - return ( aShape.ShapeType() > _shapeType ); + if ( SMESH_MesherHelper::IsSubShape( aShape, /*mainShape=*/_shape )) + return true; + + if ( aShape.ShapeType() == TopAbs_COMPOUND && + !SMESH_MesherHelper::IsSubShape( _shape, /*mainShape=*/aShape)) // issue 0020963 + { + for ( int type = TopAbs_SOLID; type < TopAbs_SHAPE; ++type ) + if ( aHyp->GetDim() == SMESH_Gen::GetShapeDim( TopAbs_ShapeEnum( type ))) + for ( TopExp_Explorer exp( aShape, TopAbs_ShapeEnum( type )); exp.More(); exp.Next()) + if ( SMESH_MesherHelper::IsSubShape( exp.Current(), /*mainShape=*/_shape )) + return true; + } + return false; } //======================================================================= @@ -347,3 +362,5 @@ SMESH_HypoFilter::~SMESH_HypoFilter() Init(0); } + + diff --git a/src/SMESH/SMESH_HypoFilter.hxx b/src/SMESH/SMESH_HypoFilter.hxx index 0fb043e57..e7c7c274b 100644 --- a/src/SMESH/SMESH_HypoFilter.hxx +++ b/src/SMESH/SMESH_HypoFilter.hxx @@ -23,7 +23,6 @@ // SMESH SMESH : implementaion of SMESH idl descriptions // File : SMESH_HypoFilter.hxx // Module : SMESH -// $Header$ // #ifndef SMESH_HypoFilter_HeaderFile #define SMESH_HypoFilter_HeaderFile @@ -78,6 +77,8 @@ class SMESH_EXPORT SMESH_HypoFilter: public SMESH_HypoPredicate static SMESH_HypoPredicate* HasDim(const int theDim); static SMESH_HypoPredicate* HasType(const int theHypType); + bool IsEmpty() const { return myPredicates.empty(); } + /*! * \brief check aHyp or/and aShape it is assigned to */ @@ -168,8 +169,8 @@ class SMESH_EXPORT SMESH_HypoFilter: public SMESH_HypoPredicate }; struct IsMoreLocalThanPredicate : public SMESH_HypoPredicate { - TopAbs_ShapeEnum _shapeType; - IsMoreLocalThanPredicate( const TopoDS_Shape& shape ):_shapeType(shape.ShapeType()){} + TopoDS_Shape _shape; + IsMoreLocalThanPredicate( const TopoDS_Shape& shape ):_shape(shape){} bool IsOk(const SMESH_Hypothesis* aHyp, const TopoDS_Shape& aShape) const; }; diff --git a/src/SMESH/SMESH_Hypothesis.cxx b/src/SMESH/SMESH_Hypothesis.cxx index 8210f156d..9ababf9e4 100644 --- a/src/SMESH/SMESH_Hypothesis.cxx +++ b/src/SMESH/SMESH_Hypothesis.cxx @@ -151,6 +151,24 @@ void SMESH_Hypothesis::SetLibName(const char* theLibName) _libName = string(theLibName); } +//======================================================================= +//function : GetMeshByPersistentID +//purpose : Find a mesh with given persistent ID +//======================================================================= + +SMESH_Mesh* SMESH_Hypothesis::GetMeshByPersistentID(int id) +{ + StudyContextStruct* myStudyContext = _gen->GetStudyContext(_studyId); + map::iterator itm = itm = myStudyContext->mapMesh.begin(); + for ( ; itm != myStudyContext->mapMesh.end(); itm++) + { + SMESH_Mesh* mesh = (*itm).second; + if ( mesh->GetMeshDS()->GetPersistentId() == id ) + return mesh; + } + return 0; +} + //============================================================================= /*! * diff --git a/src/SMESH/SMESH_Hypothesis.hxx b/src/SMESH/SMESH_Hypothesis.hxx index 1eb5ae8c8..82afd4bbc 100644 --- a/src/SMESH/SMESH_Hypothesis.hxx +++ b/src/SMESH/SMESH_Hypothesis.hxx @@ -114,6 +114,11 @@ public: virtual bool IsAuxiliary() const { return GetType() == PARAM_ALGO && _param_algo_dim < 0; } + /*! + * \brief Find a mesh with given persistent ID + */ + SMESH_Mesh* GetMeshByPersistentID(int id); + protected: SMESH_Gen* _gen; int _studyId; diff --git a/src/SMESH/SMESH_Mesh.cxx b/src/SMESH/SMESH_Mesh.cxx index 5cf9ba6c5..39c2ca976 100644 --- a/src/SMESH/SMESH_Mesh.cxx +++ b/src/SMESH/SMESH_Mesh.cxx @@ -101,6 +101,7 @@ SMESH_Mesh::SMESH_Mesh(int theLocalId, _isAutoColor = false; _isModified = false; _shapeDiagonal = 0.0; + _rmGroupCallUp = 0; _myMeshDS->ShapeToMesh( PseudoShape() ); } @@ -126,6 +127,9 @@ SMESH_Mesh::~SMESH_Mesh() delete aGroup; } _mapGroup.clear(); + + if ( _rmGroupCallUp) delete _rmGroupCallUp; + _rmGroupCallUp = 0; } //============================================================================= @@ -267,6 +271,7 @@ void SMESH_Mesh::Clear() while ( smIt->more() ) { sm = smIt->next(); sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); // for event listeners (issue 0020918) } } _isModified = false; @@ -457,6 +462,9 @@ SMESH_Hypothesis::Hypothesis_Status // NotConformAllowed can be only global if ( !isGlobalHyp ) { + // NOTE: this is not a correct way to check a name of hypothesis, + // there should be an attribute of hypothesis saying that it can/can't + // be global/local string hypName = anHyp->GetName(); if ( hypName == "NotConformAllowed" ) { @@ -499,7 +507,7 @@ SMESH_Hypothesis::Hypothesis_Status } } } - HasModificationsToDiscard(); // to reset _isModified flag if mesh become empty + HasModificationsToDiscard(); // to reset _isModified flag if a mesh becomes empty if(MYDEBUG) subMesh->DumpAlgoState(true); if(MYDEBUG) SCRUTE(ret); @@ -970,7 +978,7 @@ void SMESH_Mesh::NotifySubMeshesHypothesisModification(const SMESH_Hypothesis* h } } } - HasModificationsToDiscard(); // to reset _isModified flag if mesh become empty + HasModificationsToDiscard(); // to reset _isModified flag if mesh becomes empty } //============================================================================= @@ -1410,6 +1418,18 @@ list SMESH_Mesh::GetGroupIds() const return anIds; } +//================================================================================ +/*! + * \brief Set a caller of RemoveGroup() at level of CORBA API implementation. + * The set upCaller will be deleted by SMESH_Mesh + */ +//================================================================================ + +void SMESH_Mesh::SetRemoveGroupCallUp( TRmGroupCallUp* upCaller ) +{ + if ( _rmGroupCallUp ) delete _rmGroupCallUp; + _rmGroupCallUp = upCaller; +} //============================================================================= /*! @@ -1417,13 +1437,16 @@ list SMESH_Mesh::GetGroupIds() const */ //============================================================================= -void SMESH_Mesh::RemoveGroup (const int theGroupID) +bool SMESH_Mesh::RemoveGroup (const int theGroupID) { if (_mapGroup.find(theGroupID) == _mapGroup.end()) - return; + return false; GetMeshDS()->RemoveGroup( _mapGroup[theGroupID]->GetGroupDS() ); delete _mapGroup[theGroupID]; _mapGroup.erase (theGroupID); + if (_rmGroupCallUp) + _rmGroupCallUp->RemoveGroup( theGroupID ); + return true; } //======================================================================= @@ -1612,6 +1635,7 @@ void SMESH_Mesh::fillAncestorsMap(const TopoDS_Shape& theShape) for ( desType = TopAbs_VERTEX; desType >= memberType; desType-- ) for (TopExp_Explorer des( theShape, TopAbs_ShapeEnum( desType )); des.More(); des.Next()) { + if ( !_mapAncestors.Contains( des.Current() )) continue;// issue 0020982 TopTools_ListOfShape& ancList = _mapAncestors.ChangeFromKey( des.Current() ); TopTools_ListIteratorOfListOfShape ancIt (ancList); while ( ancIt.More() && ancIt.Value().ShapeType() >= memberType ) diff --git a/src/SMESH/SMESH_Mesh.hxx b/src/SMESH/SMESH_Mesh.hxx index ac504ced6..c88bbd02d 100644 --- a/src/SMESH/SMESH_Mesh.hxx +++ b/src/SMESH/SMESH_Mesh.hxx @@ -141,12 +141,14 @@ public: void ClearLog() throw(SALOME_Exception); - int GetId() { return _id; } + int GetId() const { return _id; } SMESHDS_Mesh * GetMeshDS() { return _myMeshDS; } - SMESH_Gen *GetGen() { return _gen; } + const SMESHDS_Mesh * GetMeshDS() const { return _myMeshDS; } + SMESH_Gen *GetGen() { return _gen; } + SMESH_subMesh *GetSubMesh(const TopoDS_Shape & aSubShape) throw(SALOME_Exception); @@ -266,10 +268,18 @@ public: SMESH_Group* GetGroup (const int theGroupID); - void RemoveGroup (const int theGroupID); + bool RemoveGroup (const int theGroupID); SMESH_Group* ConvertToStandalone ( int theGroupID ); + struct TRmGroupCallUp + { + virtual void RemoveGroup (const int theGroupID)=0; + virtual ~TRmGroupCallUp() {} + }; + void SetRemoveGroupCallUp( TRmGroupCallUp * upCaller ); + + SMDSAbs_ElementType GetElementType( const int id, const bool iselem ); void ClearMeshOrder(); @@ -303,9 +313,9 @@ protected: std::list _subMeshesUsingHypothesisList; SMESHDS_Document * _myDocument; SMESHDS_Mesh * _myMeshDS; + SMESH_Gen * _gen; std::map _mapSubMesh; std::map _mapGroup; - SMESH_Gen * _gen; bool _isAutoColor; bool _isModified; //!< modified since last total re-compute, issue 0020693 @@ -316,6 +326,11 @@ protected: TListOfListOfInt _mySubMeshOrder; + // Struct calling RemoveGroup at CORBA API implementation level, used + // to make an upper level be consistent with a lower one when group removal + // is invoked by hyp modification + TRmGroupCallUp* _rmGroupCallUp; + protected: SMESH_Mesh() {}; SMESH_Mesh(const SMESH_Mesh&) {}; diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index 6801d7d0d..f26db9a0c 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -35,6 +35,7 @@ #include "SMDS_SpacePosition.hxx" #include "SMDS_QuadraticFaceOfNodes.hxx" #include "SMDS_MeshGroup.hxx" +#include "SMDS_SetIterator.hxx" #include "SMESHDS_Group.hxx" #include "SMESHDS_Mesh.hxx" @@ -99,6 +100,8 @@ using namespace SMESH::Controls; typedef map > TElemOfNodeListMap; typedef map > TElemOfElemListMap; +typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator; + //======================================================================= //function : SMESH_MeshEditor //purpose : @@ -219,6 +222,7 @@ SMESH_MeshEditor::AddElement(const vector & node, node[16],node[17],node[18],node[19] ); } } + if ( e ) myLastCreatedElems.Append( e ); return e; } @@ -251,8 +255,8 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs // Modify a compute state of sub-meshes which become empty //======================================================================= -bool SMESH_MeshEditor::Remove (const list< int >& theIDs, - const bool isNodes ) +int SMESH_MeshEditor::Remove (const list< int >& theIDs, + const bool isNodes ) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); @@ -260,6 +264,7 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs, SMESHDS_Mesh* aMesh = GetMeshDS(); set< SMESH_subMesh *> smmap; + int removed = 0; list::const_iterator it = theIDs.begin(); for ( ; it != theIDs.end(); it++ ) { const SMDS_MeshElement * elem; @@ -296,6 +301,7 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs, aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem )); else aMesh->RemoveElement( elem ); + removed++; } // Notify sub-meshes about modification @@ -309,7 +315,7 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs, // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) ) // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); - return true; + return removed; } //======================================================================= @@ -1240,6 +1246,7 @@ namespace const int* _connectivity; //!< foursomes of tetra connectivy finished by -1 bool _baryNode; //!< additional node is to be created at cell barycenter bool _ownConn; //!< to delete _connectivity in destructor + map _faceBaryNode; //!< map face index to node at BC of face TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false) : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {} @@ -1265,7 +1272,12 @@ namespace TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags) { - int iQ = vol.Element()->IsQuadratic() ? 2 : 1; + const int iQ = vol.Element()->IsQuadratic() ? 2 : 1; + + // at HEXA_TO_24 method, each face of volume is split into triangles each based on + // an edge and a face barycenter; tertaherdons are based on triangles and + // a volume barycenter + const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 ); // Find out how adjacent volumes are split @@ -1274,7 +1286,7 @@ namespace for ( int iF = 0; iF < vol.NbFaces(); ++iF ) { int nbNodes = vol.NbFaceNodes( iF ) / iQ; - maxTetConnSize += 4 * ( nbNodes - 2 ); + maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2)); if ( nbNodes < 4 ) continue; list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ]; @@ -1312,7 +1324,7 @@ namespace // Among variants of split method select one compliant with adjacent volumes TSplitMethod method; - if ( !vol.Element()->IsPoly() ) + if ( !vol.Element()->IsPoly() && !is24TetMode ) { int nbVariants = 2, nbTet = 0; const int** connVariants = 0; @@ -1320,7 +1332,7 @@ namespace { case SMDSEntity_Hexa: case SMDSEntity_Quad_Hexa: - if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 ) + if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 ) connVariants = theHexTo5, nbTet = 5; else connVariants = theHexTo6, nbTet = 6, nbVariants = 4; @@ -1384,7 +1396,7 @@ namespace facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ])) break; } - else if ( nbNodes > 3 ) + else if ( nbNodes > 3 && !is24TetMode ) { // find the best method of splitting into triangles by aspect ratio SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio); @@ -1405,18 +1417,37 @@ namespace } if ( iCommon >= nbNodes ) iCommon = 0; // something wrong - // fill connectivity of tetra + + // fill connectivity of tetrahedra based on a current face int nbTet = nbNodes - 2; - for ( int i = 0; i < nbTet; ++i ) + if ( is24TetMode && nbNodes > 3 && triaSplits.empty()) { - int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes; - if ( !vol.IsFaceExternal( iF )) swap( i1, i2 ); - connectivity[ connSize++ ] = nInd[ iQ * iCommon ]; - connectivity[ connSize++ ] = nInd[ iQ * i1 ]; - connectivity[ connSize++ ] = nInd[ iQ * i2 ]; - connectivity[ connSize++ ] = baryCenInd; - ++method._nbTetra; + method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 )); + int faceBaryCenInd = baryCenInd + method._faceBaryNode.size(); + nbTet = nbNodes; + for ( int i = 0; i < nbTet; ++i ) + { + int i1 = i, i2 = (i+1) % nbNodes; + if ( !vol.IsFaceExternal( iF )) swap( i1, i2 ); + connectivity[ connSize++ ] = nInd[ iQ * i1 ]; + connectivity[ connSize++ ] = nInd[ iQ * i2 ]; + connectivity[ connSize++ ] = faceBaryCenInd; + connectivity[ connSize++ ] = baryCenInd; + } } + else + { + for ( int i = 0; i < nbTet; ++i ) + { + int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes; + if ( !vol.IsFaceExternal( iF )) swap( i1, i2 ); + connectivity[ connSize++ ] = nInd[ iQ * iCommon ]; + connectivity[ connSize++ ] = nInd[ iQ * i1 ]; + connectivity[ connSize++ ] = nInd[ iQ * i2 ]; + connectivity[ connSize++ ] = baryCenInd; + } + } + method._nbTetra += nbTet; } connectivity[ connSize++ ] = -1; } @@ -1451,6 +1482,29 @@ namespace } return false; } + + //======================================================================= + /*! + * \brief A key of a face of volume + */ + //======================================================================= + + struct TVolumeFaceKey: pair< int, pair< int, int> > + { + TVolumeFaceKey( SMDS_VolumeTool& vol, int iF ) + { + TIDSortedNodeSet sortedNodes; + const int iQ = vol.Element()->IsQuadratic() ? 2 : 1; + int nbNodes = vol.NbFaceNodes( iF ); + const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF ); + for ( int i = 0; i < nbNodes; i += iQ ) + sortedNodes.insert( fNodes[i] ); + TIDSortedNodeSet::iterator n = sortedNodes.begin(); + first = (*(n++))->GetID(); + second.first = (*(n++))->GetID(); + second.second = (*(n++))->GetID(); + } + }; } // namespace //======================================================================= @@ -1473,6 +1527,10 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, SMESH_SequenceOfElemPtr newNodes, newElems; + // map face of volume to it's baricenrtic node + map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode; + double bc[3]; + TIDSortedElemSet::const_iterator elem = theElems.begin(); for ( ; elem != theElems.end(); ++elem ) { @@ -1485,7 +1543,7 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags ); if ( splitMethod._nbTetra < 1 ) continue; - // find submesh to add new tetras in + // find submesh to add new tetras to if ( !subMesh || !subMesh->Contains( *elem )) { int shapeID = FindShape( *elem ); @@ -1514,12 +1572,28 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, if ( splitMethod._baryNode ) { // make a node at barycenter - gp_XYZ gc( 0,0,0 ); - gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size(); - SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() ); + volTool.GetBaryCenter( bc[0], bc[1], bc[2] ); + SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] ); nodes.push_back( gcNode ); newNodes.Append( gcNode ); } + if ( !splitMethod._faceBaryNode.empty() ) + { + // make or find baricentric nodes of faces + map::iterator iF_n = splitMethod._faceBaryNode.begin(); + for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n ) + { + map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n = + volFace2BaryNode.insert + ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first; + if ( !f_n->second ) + { + volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] ); + newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] )); + } + nodes.push_back( iF_n->second = f_n->second ); + } + } // make tetras helper.SetElementsOnShape( true ); @@ -1546,48 +1620,69 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, volTool.GetFaceNodes( iF ) + nbNodes*iQ ); while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes )) { - // among possible triangles create ones discribed by split method - const int* nInd = volTool.GetFaceNodesIndices( iF ); - int nbVariants = ( nbNodes == 4 ? 2 : nbNodes ); - int iCom = 0; // common node of triangle faces to split into - list< TTriangleFacet > facets; - for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom ) + // make triangles + helper.SetElementsOnShape( false ); + vector< const SMDS_MeshElement* > triangles; + + map::iterator iF_n = splitMethod._faceBaryNode.find(iF); + if ( iF_n != splitMethod._faceBaryNode.end() ) { - TTriangleFacet t012( nInd[ iQ * ( iCom )], - nInd[ iQ * ( (iCom+1)%nbNodes )], - nInd[ iQ * ( (iCom+2)%nbNodes )]); - TTriangleFacet t023( nInd[ iQ * ( iCom )], - nInd[ iQ * ( (iCom+2)%nbNodes )], - nInd[ iQ * ( (iCom+3)%nbNodes )]); - if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 )) + for ( int iN = 0; iN < nbNodes*iQ; iN += iQ ) { - facets.push_back( t012 ); - facets.push_back( t023 ); - for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast ) - facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )], - nInd[ iQ * ((iLast-1)%nbNodes )], - nInd[ iQ * ((iLast )%nbNodes )])); - break; + const SMDS_MeshNode* n1 = fNodes[iN]; + const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ]; + const SMDS_MeshNode *n3 = iF_n->second; + if ( !volTool.IsFaceExternal( iF )) + swap( n2, n3 ); + triangles.push_back( helper.AddFace( n1,n2,n3 )); + } + } + else + { + // among possible triangles create ones discribed by split method + const int* nInd = volTool.GetFaceNodesIndices( iF ); + int nbVariants = ( nbNodes == 4 ? 2 : nbNodes ); + int iCom = 0; // common node of triangle faces to split into + list< TTriangleFacet > facets; + for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom ) + { + TTriangleFacet t012( nInd[ iQ * ( iCom )], + nInd[ iQ * ( (iCom+1)%nbNodes )], + nInd[ iQ * ( (iCom+2)%nbNodes )]); + TTriangleFacet t023( nInd[ iQ * ( iCom )], + nInd[ iQ * ( (iCom+2)%nbNodes )], + nInd[ iQ * ( (iCom+3)%nbNodes )]); + if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 )) + { + facets.push_back( t012 ); + facets.push_back( t023 ); + for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast ) + facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )], + nInd[ iQ * ((iLast-1)%nbNodes )], + nInd[ iQ * ((iLast )%nbNodes )])); + break; + } + } + list< TTriangleFacet >::iterator facet = facets.begin(); + for ( ; facet != facets.end(); ++facet ) + { + if ( !volTool.IsFaceExternal( iF )) + swap( facet->_n2, facet->_n3 ); + triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ], + volNodes[ facet->_n2 ], + volNodes[ facet->_n3 ])); } } - // find submesh to add new faces in + // find submesh to add new triangles in if ( !fSubMesh || !fSubMesh->Contains( face )) { int shapeID = FindShape( face ); fSubMesh = GetMeshDS()->MeshElements( shapeID ); } - // make triangles - helper.SetElementsOnShape( false ); - vector< const SMDS_MeshElement* > triangles; - list< TTriangleFacet >::iterator facet = facets.begin(); - for ( ; facet != facets.end(); ++facet ) + for ( int i = 0; i < triangles.size(); ++i ) { - if ( !volTool.IsFaceExternal( iF )) - swap( facet->_n2, facet->_n3 ); - triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ], - volNodes[ facet->_n2 ], - volNodes[ facet->_n3 ])); - if ( triangles.back() && fSubMesh ) + if ( !triangles.back() ) continue; + if ( fSubMesh ) fSubMesh->AddElement( triangles.back()); newElems.Append( triangles.back() ); } @@ -5106,10 +5201,17 @@ void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps, } -//======================================================================= -//function : Transform -//purpose : -//======================================================================= +//================================================================================ +/*! + * \brief Move or copy theElements applying theTrsf to their nodes + * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes + * \param theTrsf - transformation to apply + * \param theCopy - if true, create translated copies of theElems + * \param theMakeGroups - if true and theCopy, create translated groups + * \param theTargetMesh - mesh to copy translated elements into + * \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups + */ +//================================================================================ SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, @@ -5137,6 +5239,7 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, groupPostfix = "translated"; break; case gp_Scale: + case gp_CompoundTrsf: // different scale by axis groupPostfix = "scaled"; break; default: @@ -5159,7 +5262,36 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, // source elements for each generated one SMESH_SequenceOfElemPtr srcElems, srcNodes; - // loop on theElems + // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh + list orphanCopy; // copies of orphan nodes + vector orphanNode; // original orphan nodes + + if ( theElems.empty() ) // transform the whole mesh + { + // add all elements + SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator(); + while ( eIt->more() ) theElems.insert( eIt->next() ); + // add orphan nodes + SMDS_MeshElementIDFactory idFactory; + SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator(); + while ( nIt->more() ) + { + const SMDS_MeshNode* node = nIt->next(); + if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second ) + { + // node was not inserted into theElems because an element with the same ID + // is already there. As a work around we insert a copy of node with + // an ID = - + orphanCopy.push_back( *node ); // copy node + SMDS_MeshNode* nodeCopy = &orphanCopy.back(); + int uniqueID = -orphanNode.size(); + orphanNode.push_back( node ); + idFactory.BindID( uniqueID, nodeCopy ); + theElems.insert( nodeCopy ); + } + } + } + // loop on theElems to transorm nodes TIDSortedElemSet::iterator itElem; for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { const SMDS_MeshElement* elem = *itElem; @@ -5170,8 +5302,10 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, SMDS_ElemIteratorPtr itN = elem->nodesIterator(); while ( itN->more() ) { - // check if a node has been already transformed const SMDS_MeshNode* node = cast2Node( itN->next() ); + if ( node->GetID() < 0 ) + node = orphanNode[ -node->GetID() ]; + // check if a node has been already transformed pair n2n_isnew = nodeMap.insert( make_pair ( node, node )); if ( !n2n_isnew.second ) @@ -5401,10 +5535,8 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, } } else if ( theCopy ) { - if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) { - myLastCreatedElems.Append( copy ); + if ( AddElement( nodes, elem->GetType(), elem->IsPoly() )) srcElems.Append( elem ); - } } else { // reverse element as it was reversed by transformation @@ -5422,331 +5554,6 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, return newGroupIDs; } - -//======================================================================= -//function : Scale -//purpose : -//======================================================================= - -SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems, - const gp_Pnt& thePoint, - const std::list& theScaleFact, - const bool theCopy, - const bool theMakeGroups, - SMESH_Mesh* theTargetMesh) -{ - myLastCreatedElems.Clear(); - myLastCreatedNodes.Clear(); - - SMESH_MeshEditor targetMeshEditor( theTargetMesh ); - SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0; - SMESHDS_Mesh* aMesh = GetMeshDS(); - - double scaleX=1.0, scaleY=1.0, scaleZ=1.0; - std::list::const_iterator itS = theScaleFact.begin(); - scaleX = (*itS); - if(theScaleFact.size()==1) { - scaleY = (*itS); - scaleZ= (*itS); - } - if(theScaleFact.size()==2) { - itS++; - scaleY = (*itS); - scaleZ= (*itS); - } - if(theScaleFact.size()>2) { - itS++; - scaleY = (*itS); - itS++; - scaleZ= (*itS); - } - - // map old node to new one - TNodeNodeMap nodeMap; - - // elements sharing moved nodes; those of them which have all - // nodes mirrored but are not in theElems are to be reversed - TIDSortedElemSet inverseElemSet; - - // source elements for each generated one - SMESH_SequenceOfElemPtr srcElems, srcNodes; - - // loop on theElems - TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - if ( !elem ) - continue; - - // loop on elem nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - - // check if a node has been already transformed - const SMDS_MeshNode* node = cast2Node( itN->next() ); - pair n2n_isnew = - nodeMap.insert( make_pair ( node, node )); - if ( !n2n_isnew.second ) - continue; - - //double coord[3]; - //coord[0] = node->X(); - //coord[1] = node->Y(); - //coord[2] = node->Z(); - //theTrsf.Transforms( coord[0], coord[1], coord[2] ); - double dx = (node->X() - thePoint.X()) * scaleX; - double dy = (node->Y() - thePoint.Y()) * scaleY; - double dz = (node->Z() - thePoint.Z()) * scaleZ; - if ( theTargetMesh ) { - //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] ); - const SMDS_MeshNode * newNode = - aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz ); - n2n_isnew.first->second = newNode; - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - } - else if ( theCopy ) { - //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - const SMDS_MeshNode * newNode = - aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz ); - n2n_isnew.first->second = newNode; - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - } - else { - //aMesh->MoveNode( node, coord[0], coord[1], coord[2] ); - aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz ); - // node position on shape becomes invalid - const_cast< SMDS_MeshNode* > ( node )->SetPosition - ( SMDS_SpacePosition::originSpacePosition() ); - } - - // keep inverse elements - //if ( !theCopy && !theTargetMesh && needReverse ) { - // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator(); - // while ( invElemIt->more() ) { - // const SMDS_MeshElement* iel = invElemIt->next(); - // inverseElemSet.insert( iel ); - // } - //} - } - } - - // either create new elements or reverse mirrored ones - //if ( !theCopy && !needReverse && !theTargetMesh ) - if ( !theCopy && !theTargetMesh ) - return PGroupIDs(); - - TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin(); - for ( ; invElemIt != inverseElemSet.end(); invElemIt++ ) - theElems.insert( *invElemIt ); - - // replicate or reverse elements - - enum { - REV_TETRA = 0, // = nbNodes - 4 - REV_PYRAMID = 1, // = nbNodes - 4 - REV_PENTA = 2, // = nbNodes - 4 - REV_FACE = 3, - REV_HEXA = 4, // = nbNodes - 4 - FORWARD = 5 - }; - int index[][8] = { - { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA - { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID - { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA - { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE - { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA - { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD - }; - - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) - { - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() == SMDSAbs_Node ) - continue; - - int nbNodes = elem->NbNodes(); - int elemType = elem->GetType(); - - if (elem->IsPoly()) { - // Polygon or Polyhedral Volume - switch ( elemType ) { - case SMDSAbs_Face: - { - vector poly_nodes (nbNodes); - int iNode = 0; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while (itN->more()) { - const SMDS_MeshNode* node = - static_cast(itN->next()); - TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); - if (nodeMapIt == nodeMap.end()) - break; // not all nodes transformed - //if (needReverse) { - // // reverse mirrored faces and volumes - // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second; - //} else { - poly_nodes[iNode] = (*nodeMapIt).second; - //} - iNode++; - } - if ( iNode != nbNodes ) - continue; // not all nodes transformed - - if ( theTargetMesh ) { - myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes)); - srcElems.Append( elem ); - } - else if ( theCopy ) { - myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes)); - srcElems.Append( elem ); - } - else { - aMesh->ChangePolygonNodes(elem, poly_nodes); - } - } - break; - case SMDSAbs_Volume: - { - // ATTENTION: Reversing is not yet done!!! - const SMDS_PolyhedralVolumeOfNodes* aPolyedre = - dynamic_cast( elem ); - if (!aPolyedre) { - MESSAGE("Warning: bad volumic element"); - continue; - } - - vector poly_nodes; - vector quantities; - - bool allTransformed = true; - int nbFaces = aPolyedre->NbFaces(); - for (int iface = 1; iface <= nbFaces && allTransformed; iface++) { - int nbFaceNodes = aPolyedre->NbFaceNodes(iface); - for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) { - const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode); - TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); - if (nodeMapIt == nodeMap.end()) { - allTransformed = false; // not all nodes transformed - } else { - poly_nodes.push_back((*nodeMapIt).second); - } - } - quantities.push_back(nbFaceNodes); - } - if ( !allTransformed ) - continue; // not all nodes transformed - - if ( theTargetMesh ) { - myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities)); - srcElems.Append( elem ); - } - else if ( theCopy ) { - myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities)); - srcElems.Append( elem ); - } - else { - aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); - } - } - break; - default:; - } - continue; - } - - // Regular elements - int* i = index[ FORWARD ]; - //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes - // if ( elemType == SMDSAbs_Face ) - // i = index[ REV_FACE ]; - // else - // i = index[ nbNodes - 4 ]; - - if(elem->IsQuadratic()) { - static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; - i = anIds; - //if(needReverse) { - // if(nbNodes==3) { // quadratic edge - // static int anIds[] = {1,0,2}; - // i = anIds; - // } - // else if(nbNodes==6) { // quadratic triangle - // static int anIds[] = {0,2,1,5,4,3}; - // i = anIds; - // } - // else if(nbNodes==8) { // quadratic quadrangle - // static int anIds[] = {0,3,2,1,7,6,5,4}; - // i = anIds; - // } - // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes - // static int anIds[] = {0,2,1,3,6,5,4,7,9,8}; - // i = anIds; - // } - // else if(nbNodes==13) { // quadratic pyramid of 13 nodes - // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10}; - // i = anIds; - // } - // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes - // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13}; - // i = anIds; - // } - // else { // nbNodes==20 - quadratic hexahedron with 20 nodes - // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17}; - // i = anIds; - // } - //} - } - - // find transformed nodes - vector nodes(nbNodes); - int iNode = 0; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - const SMDS_MeshNode* node = - static_cast( itN->next() ); - TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node ); - if ( nodeMapIt == nodeMap.end() ) - break; // not all nodes transformed - nodes[ i [ iNode++ ]] = (*nodeMapIt).second; - } - if ( iNode != nbNodes ) - continue; // not all nodes transformed - - if ( theTargetMesh ) { - if ( SMDS_MeshElement* copy = - targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) { - myLastCreatedElems.Append( copy ); - srcElems.Append( elem ); - } - } - else if ( theCopy ) { - if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) { - myLastCreatedElems.Append( copy ); - srcElems.Append( elem ); - } - } - else { - // reverse element as it was reversed by transformation - if ( nbNodes > 2 ) - aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes ); - } - } - - PGroupIDs newGroupIDs; - - if ( theMakeGroups && theCopy || - theMakeGroups && theTargetMesh ) { - string groupPostfix = "scaled"; - newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh ); - } - - return newGroupIDs; -} - - //======================================================================= /*! * \brief Create groups of elements made during transformation @@ -5881,24 +5688,21 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, */ //================================================================================ -void SMESH_MeshEditor::FindCoincidentNodes (set & theNodes, - const double theTolerance, - TListOfListOfNodes & theGroupsOfNodes) +void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes, + const double theTolerance, + TListOfListOfNodes & theGroupsOfNodes) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); - set nodes; if ( theNodes.empty() ) { // get all nodes in the mesh - SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(); + SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true); while ( nIt->more() ) - nodes.insert( nodes.end(),nIt->next()); + theNodes.insert( theNodes.end(),nIt->next()); } - else - nodes=theNodes; - SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance); + SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance); } @@ -5918,9 +5722,9 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher { myMesh = ( SMESHDS_Mesh* ) theMesh; - set nodes; + TIDSortedNodeSet nodes; if ( theMesh ) { - SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(); + SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true); while ( nIt->more() ) nodes.insert( nodes.end(), nIt->next() ); } @@ -5972,12 +5776,13 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher treeList.push_back( myOctreeNode ); SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() ); + bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize ); for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt) { SMESH_OctreeNode* tree = *trIt; if ( !tree->isLeaf() ) // put children to the queue { - if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue; + if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue; SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator(); while ( cIt->more() ) treeList.push_back( cIt->next() ); @@ -6068,7 +5873,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() { public: - ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType); + ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius ); void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems); void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems); ~ElementBndBoxTree(); @@ -6084,7 +5889,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() { const SMDS_MeshElement* _element; int _refCount; // an ElementBox can be included in several tree branches - ElementBox(const SMDS_MeshElement* elem); + ElementBox(const SMDS_MeshElement* elem, double tolerance); }; vector< ElementBox* > _elements; }; @@ -6095,7 +5900,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() */ //================================================================================ - ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType) + ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance) :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. )) { int nbElems = mesh.GetMeshInfo().NbElements( elemType ); @@ -6103,7 +5908,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType ); while ( elemIt->more() ) - _elements.push_back( new ElementBox( elemIt->next() )); + _elements.push_back( new ElementBox( elemIt->next(),tolerance )); if ( _elements.size() > MaxNbElemsInLeaf ) compute(); @@ -6227,14 +6032,14 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() */ //================================================================================ - ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem) + ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance) { _element = elem; _refCount = 1; SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); while ( nIt->more() ) Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() ))); - Enlarge( NodeRadius ); + Enlarge( tolerance ); } } // namespace @@ -6268,6 +6073,9 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher vector< const SMDS_MeshElement* >& foundElements); virtual TopAbs_State GetPointState(const gp_Pnt& point); + void GetElementsNearLine( const gp_Ax1& line, + SMDSAbs_ElementType type, + vector< const SMDS_MeshElement* >& foundElems); double getTolerance(); bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face, const double tolerance, double & param); @@ -6276,7 +6084,7 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher { return _outerFaces.empty() || _outerFaces.count(face); } - struct TInters //!< data of intersection of the line and the mesh face used in GetPointState() + struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState()) { const SMDS_MeshElement* _face; gp_Vec _faceNorm; @@ -6351,7 +6159,7 @@ double SMESH_ElementSearcherImpl::getTolerance() elemSize = max( dist, elemSize ); } } - _tolerance = 1e-6 * elemSize; + _tolerance = 1e-4 * elemSize; } } return _tolerance; @@ -6542,7 +6350,7 @@ FindElementsByPoint(const gp_Pnt& point, if ( !_ebbTree || _elementType != type ) { if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type ); + _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance ); } TIDSortedElemSet suspectElems; _ebbTree->getElementsNearPoint( point, suspectElems ); @@ -6777,6 +6585,26 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) return TopAbs_UNKNOWN; } +//======================================================================= +/*! + * \brief Return elements possibly intersecting the line + */ +//======================================================================= + +void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line, + SMDSAbs_ElementType type, + vector< const SMDS_MeshElement* >& foundElems) +{ + if ( !_ebbTree || _elementType != type ) + { + if ( _ebbTree ) delete _ebbTree; + _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type ); + } + TIDSortedElemSet suspectFaces; // elements possibly intersecting the line + _ebbTree->getElementsNearLine( line, suspectFaces ); + foundElems.assign( suspectFaces.begin(), suspectFaces.end()); +} + //======================================================================= /*! * \brief Return SMESH_ElementSearcher @@ -8860,7 +8688,7 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, int nbElem = 0; if( !theSm ) return nbElem; - const bool notFromGroups = false; + vector nbNodeInFaces; SMDS_ElemIteratorPtr ElemItr = theSm->GetElements(); while(ElemItr->more()) { @@ -8870,15 +8698,13 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, int id = elem->GetID(); int nbNodes = elem->NbNodes(); - vector aNds (nbNodes); - - for(int i = 0; i < nbNodes; i++) - { - aNds[i] = elem->GetNode(i); - } SMDSAbs_ElementType aType = elem->GetType(); - GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups); + vector nodes (elem->begin_nodes(), elem->end_nodes()); + if ( elem->GetEntityType() == SMDSEntity_Polyhedra ) + nbNodeInFaces = static_cast( elem )->GetQuanities(); + + GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false); const SMDS_MeshElement* NewElem = 0; @@ -8886,7 +8712,7 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, { case SMDSAbs_Edge : { - NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d); + NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d); break; } case SMDSAbs_Face : @@ -8894,12 +8720,13 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, switch(nbNodes) { case 3: - NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d); + NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d); break; case 4: - NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d); + NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); break; default: + NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d); continue; } break; @@ -8909,20 +8736,20 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, switch(nbNodes) { case 4: - NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d); + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); break; case 5: - NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d); + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d); break; case 6: - NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d); + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d); break; case 8: - NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], - aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d); + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d); break; default: - continue; + NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d); } break; } @@ -8946,7 +8773,6 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) SMESH_MesherHelper aHelper(*myMesh); aHelper.SetIsQuadratic( true ); - const bool notFromGroups = false; int nbCheckedElems = 0; if ( myMesh->HasShapeToMesh() ) @@ -8977,7 +8803,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) const SMDS_MeshNode* n1 = edge->GetNode(0); const SMDS_MeshNode* n2 = edge->GetNode(1); - meshDS->RemoveFreeElement(edge, smDS, notFromGroups); + meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false); const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d); ReplaceElemInGroups( edge, NewEdge, GetMeshDS()); @@ -8991,29 +8817,25 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) int id = face->GetID(); int nbNodes = face->NbNodes(); - vector aNds (nbNodes); + vector nodes ( face->begin_nodes(), face->end_nodes()); - for(int i = 0; i < nbNodes; i++) - { - aNds[i] = face->GetNode(i); - } - - meshDS->RemoveFreeElement(face, smDS, notFromGroups); + meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false); SMDS_MeshFace * NewFace = 0; switch(nbNodes) { case 3: - NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d); + NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d); break; case 4: - NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d); + NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); break; default: - continue; + NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d); } ReplaceElemInGroups( face, NewFace, GetMeshDS()); } + vector nbNodeInFaces; SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator(); while(aVolumeItr->more()) { @@ -9022,42 +8844,41 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) int id = volume->GetID(); int nbNodes = volume->NbNodes(); - vector aNds (nbNodes); - - for(int i = 0; i < nbNodes; i++) - { - aNds[i] = volume->GetNode(i); - } + vector nodes (volume->begin_nodes(), volume->end_nodes()); + if ( volume->GetEntityType() == SMDSEntity_Polyhedra ) + nbNodeInFaces = static_cast(volume)->GetQuanities(); - meshDS->RemoveFreeElement(volume, smDS, notFromGroups); + meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false); SMDS_MeshVolume * NewVolume = 0; switch(nbNodes) { case 4: - NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], - aNds[3], id, theForce3d ); + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], + nodes[3], id, theForce3d ); break; case 5: - NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], - aNds[3], aNds[4], id, theForce3d); + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], + nodes[3], nodes[4], id, theForce3d); break; case 6: - NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], - aNds[3], aNds[4], aNds[5], id, theForce3d); + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], + nodes[3], nodes[4], nodes[5], id, theForce3d); break; case 8: - NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], - aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d); + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d); break; default: - continue; + NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d); } ReplaceElemInGroups(volume, NewVolume, meshDS); } } - if ( !theForce3d && !getenv("NO_FixQuadraticElements")) { - aHelper.SetSubShape(0); // apply to the whole mesh + + if ( !theForce3d && !getenv("NO_FixQuadraticElements")) + { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion + aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh aHelper.FixQuadraticElements(); } } @@ -9085,8 +8906,8 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, { int id = elem->GetID(); int nbNodes = elem->NbNodes(); - vector aNds, mediumNodes; - aNds.reserve( nbNodes ); + vector nodes, mediumNodes; + nodes.reserve( nbNodes ); mediumNodes.reserve( nbNodes ); for(int i = 0; i < nbNodes; i++) @@ -9096,15 +8917,15 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, if( elem->IsMediumNode( n ) ) mediumNodes.push_back( n ); else - aNds.push_back( n ); + nodes.push_back( n ); } - if( aNds.empty() ) continue; + if( nodes.empty() ) continue; SMDSAbs_ElementType aType = elem->GetType(); //remove old quadratic element meshDS->RemoveFreeElement( elem, theSm, notFromGroups ); - SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id ); + SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id ); ReplaceElemInGroups(elem, NewElem, meshDS); if( theSm && NewElem ) theSm->AddElement( NewElem ); @@ -10010,7 +9831,7 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, continue; if ( theIsDoubleElem ) - myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) ); + AddElement(newNodes, anElem->GetType(), anElem->IsPoly()); else theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() ); @@ -10235,7 +10056,7 @@ bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems, //================================================================================ /*! - * \brief Generated skin mesh (containing 2D cells) from 3D mesh + * \brief Generates skin mesh (containing 2D cells) from 3D mesh * The created 2D mesh elements based on nodes of free faces of boundary volumes * \return TRUE if operation has been completed successfully, FALSE otherwise */ @@ -10277,9 +10098,195 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D() nbExisted++; continue; // face already exsist } - myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) ); + AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1); nbCreated++; } } return ( nbFree==(nbExisted+nbCreated) ); } + +namespace +{ + inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node) + { + if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() )) + return n; + return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() ); + } +} +//================================================================================ +/*! + * \brief Creates missing boundary elements + * \param elements - elements whose boundary is to be checked + * \param dimension - defines type of boundary elements to create + * \param group - a group to store created boundary elements in + * \param targetMesh - a mesh to store created boundary elements in + * \param toCopyElements - if true, the checked elements will be copied into the targetMesh + * \param toCopyExistingBondary - if true, not only new but also pre-existing + * boundary elements will be copied into the targetMesh + */ +//================================================================================ + +void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, + Bnd_Dimension dimension, + SMESH_Group* group/*=0*/, + SMESH_Mesh* targetMesh/*=0*/, + bool toCopyElements/*=false*/, + bool toCopyExistingBondary/*=false*/) +{ + SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge; + SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume; + // hope that all elements are of the same type, do not check them all + if ( !elements.empty() && (*elements.begin())->GetType() != elemType ) + throw SALOME_Exception(LOCALIZED("wrong element type")); + + if ( !targetMesh ) + toCopyElements = toCopyExistingBondary = false; + + SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh ); + SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS(); + + SMDS_VolumeTool vTool; + TIDSortedElemSet emptySet, avoidSet; + int inode; + + typedef vector TConnectivity; + + SMDS_ElemIteratorPtr eIt; + if (elements.empty()) + eIt = aMesh->elementsIterator(elemType); + else + eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() )); + + while (eIt->more()) + { + const SMDS_MeshElement* elem = eIt->next(); + const int iQuad = elem->IsQuadratic(); + + // 1. For an elem, get present bnd elements and connectivities of missing bnd elements + vector presentBndElems; + vector missingBndElems; + TConnectivity nodes; + if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------ + { + vTool.SetExternalNormal(); + for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ ) + { + if (!vTool.IsFreeFace(iface)) + continue; + int nbFaceNodes = vTool.NbFaceNodes(iface); + const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface); + if ( missType == SMDSAbs_Edge ) // boundary edges + { + nodes.resize( 2+iQuad ); + for ( int i = 0; i < nbFaceNodes; i += 1+iQuad) + { + for ( int j = 0; j < nodes.size(); ++j ) + nodes[j] =nn[i+j]; + if ( const SMDS_MeshElement* edge = + aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0)) + presentBndElems.push_back( edge ); + else + missingBndElems.push_back( nodes ); + } + } + else // boundary face + { + nodes.clear(); + for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad) + nodes.push_back( nn[inode] ); + if (iQuad) + for ( inode = 1; inode < nbFaceNodes; inode += 2) + nodes.push_back( nn[inode] ); + + if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) ) + presentBndElems.push_back( f ); + else + missingBndElems.push_back( nodes ); + } + } + } + else // elem is a face ------------------------------------------ + { + avoidSet.clear(), avoidSet.insert( elem ); + int nbNodes = elem->NbCornerNodes(); + nodes.resize( 2 /*+ iQuad*/); + for ( int i = 0; i < nbNodes; i++ ) + { + nodes[0] = elem->GetNode(i); + nodes[1] = elem->GetNode((i+1)%nbNodes); + if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet)) + continue; // not free link + + //if ( iQuad ) + //nodes[2] = elem->GetNode( i + nbNodes ); + if ( const SMDS_MeshElement* edge = + aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true)) + presentBndElems.push_back( edge ); + else + missingBndElems.push_back( nodes ); + } + } + + // 2. Add missing boundary elements + if ( targetMesh != myMesh ) + // instead of making a map of nodes in this mesh and targetMesh, + // we create nodes with same IDs. We can renumber them later, if needed + for ( int i = 0; i < missingBndElems.size(); ++i ) + { + TConnectivity& srcNodes = missingBndElems[i]; + TConnectivity nodes( srcNodes.size() ); + for ( inode = 0; inode < nodes.size(); ++inode ) + nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] ); + tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4); + } + else + for ( int i = 0; i < missingBndElems.size(); ++i ) + { + TConnectivity& nodes = missingBndElems[i]; + tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4); + } + + // 3. Copy present boundary elements + if ( toCopyExistingBondary ) + for ( int i = 0 ; i < presentBndElems.size(); ++i ) + { + const SMDS_MeshElement* e = presentBndElems[i]; + TConnectivity nodes( e->NbNodes() ); + for ( inode = 0; inode < nodes.size(); ++inode ) + nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) ); + tgtEditor.AddElement(nodes, missType, e->IsPoly()); + // leave only missing elements in tgtEditor.myLastCreatedElems + tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() ); + } + } // loop on given elements + + // 4. Fill group with missing boundary elements + if ( group ) + { + if ( SMESHDS_Group* g = dynamic_cast( group->GetGroupDS() )) + for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i ) + g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 )); + } + tgtEditor.myLastCreatedElems.Clear(); + + // 5. Copy given elements + if ( toCopyElements ) + { + if (elements.empty()) + eIt = aMesh->elementsIterator(elemType); + else + eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() )); + while (eIt->more()) + { + const SMDS_MeshElement* elem = eIt->next(); + TConnectivity nodes( elem->NbNodes() ); + for ( inode = 0; inode < nodes.size(); ++inode ) + nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) ); + tgtEditor.AddElement(nodes, elemType, elem->IsPoly()); + + tgtEditor.myLastCreatedElems.Clear(); + } + } + return; +} diff --git a/src/SMESH/SMESH_MeshEditor.hxx b/src/SMESH/SMESH_MeshEditor.hxx index d9f4b5d28..dabe3f8db 100644 --- a/src/SMESH/SMESH_MeshEditor.hxx +++ b/src/SMESH/SMESH_MeshEditor.hxx @@ -60,6 +60,7 @@ typedef std::map TNodeNodeMap; //!< Set of elements sorted by ID, to be used to assure predictability of edition typedef std::set< const SMDS_MeshElement*, TIDCompare > TIDSortedElemSet; +typedef std::set< const SMDS_MeshNode*, TIDCompare > TIDSortedNodeSet; typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink; @@ -92,6 +93,13 @@ struct SMESH_ElementSearcher std::vector< const SMDS_MeshElement* >& foundElems)=0; virtual TopAbs_State GetPointState(const gp_Pnt& point) = 0; + + /*! + * \brief Return elements possibly intersecting the line + */ + virtual void GetElementsNearLine( const gp_Ax1& line, + SMDSAbs_ElementType type, + std::vector< const SMDS_MeshElement* >& foundElems)=0; }; //======================================================================= @@ -171,7 +179,7 @@ public: const bool isPoly, const int ID = 0); - bool Remove (const std::list< int >& theElemIDs, const bool isNodes); + int Remove (const std::list< int >& theElemIDs, const bool isNodes); // Remove a node or an element. // Modify a compute state of sub-meshes which become empty @@ -237,7 +245,7 @@ public: SMESH::Controls::NumericalFunctorPtr theCriterion); - enum SplitVolumToTetraFlags { HEXA_TO_5 = 1, HEXA_TO_6 = 2 };//!& theScaleFact, - const bool theCopy, - const bool theMakeGroups, - SMESH_Mesh* theTargetMesh=0); - typedef std::list< std::list< const SMDS_MeshNode* > > TListOfListOfNodes; - void FindCoincidentNodes (std::set & theNodes, - const double theTolerance, - TListOfListOfNodes & theGroupsOfNodes); + void FindCoincidentNodes (TIDSortedNodeSet & theNodes, + const double theTolerance, + TListOfListOfNodes & theGroupsOfNodes); // Return list of group of nodes close to each other within theTolerance. // Search among theNodes or in the whole mesh if theNodes is empty. /*! - * \brief Return SMESH_NodeSearcher + * \brief Return SMESH_NodeSearcher. The caller is responsible for deleteing it */ SMESH_NodeSearcher* GetNodeSearcher(); /*! - * \brief Return SMESH_ElementSearcher + * \brief Return SMESH_ElementSearcher. The caller is responsible for deleteing it */ SMESH_ElementSearcher* GetElementSearcher(); /*! @@ -532,12 +523,18 @@ public: // theBetweenNode1 - theBetweenNode2, between theBetweenNode1 and theBetweenNode2. void ConvertToQuadratic(const bool theForce3d); - //converts all mesh to quadratic one, deletes old elements, replacing - //them with quadratic ones with the same id. + // Converts all mesh to quadratic one, deletes old elements, replacing + // them with quadratic ones with the same id. + // If 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 + // If theForce3d = 0; this results in the medium node lying at the + // geometrical edge from which the mesh element is built bool ConvertFromQuadratic(); - //converts all mesh from quadratic to ordinary ones, deletes old quadratic elements, replacing - //them with ordinary mesh elements with the same id. + // Converts all mesh from quadratic to ordinary ones, deletes old quadratic elements, replacing + // them with ordinary mesh elements with the same id. + // Returns true in case of success, false otherwise. static void AddToSameGroups (const SMDS_MeshElement* elemToAdd, const SMDS_MeshElement* elemInGroups, @@ -627,13 +624,17 @@ public: const TIDSortedElemSet& theNodesNot, const TopoDS_Shape& theShape ); - /*! - * \brief Generated skin mesh (containing 2D cells) from 3D mesh - * The created 2D mesh elements based on nodes of free faces of boundary volumes - * \return TRUE if operation has been completed successfully, FALSE otherwise - */ bool Make2DMeshFrom3D(); - + + enum Bnd_Dimension { BND_2DFROM3D, BND_1DFROM3D, BND_1DFROM2D }; + + void MakeBoundaryMesh(const TIDSortedElemSet& elements, + Bnd_Dimension dimension, + SMESH_Group* group = 0, + SMESH_Mesh* targetMesh = 0, + bool toCopyElements = false, + bool toCopyExistingBondary = false); + private: /*! diff --git a/src/SMESH/SMESH_MesherHelper.cxx b/src/SMESH/SMESH_MesherHelper.cxx index 8cdacf7ed..bb96f0352 100644 --- a/src/SMESH/SMESH_MesherHelper.cxx +++ b/src/SMESH/SMESH_MesherHelper.cxx @@ -89,9 +89,16 @@ SMESH_MesherHelper::SMESH_MesherHelper(SMESH_Mesh& theMesh) SMESH_MesherHelper::~SMESH_MesherHelper() { - TID2Projector::iterator i_proj = myFace2Projector.begin(); - for ( ; i_proj != myFace2Projector.end(); ++i_proj ) - delete i_proj->second; + { + TID2ProjectorOnSurf::iterator i_proj = myFace2Projector.begin(); + for ( ; i_proj != myFace2Projector.end(); ++i_proj ) + delete i_proj->second; + } + { + TID2ProjectorOnCurve::iterator i_proj = myEdge2Projector.begin(); + for ( ; i_proj != myEdge2Projector.end(); ++i_proj ) + delete i_proj->second; + } } //======================================================================= @@ -356,7 +363,7 @@ gp_XY SMESH_MesherHelper::GetNodeUV(const TopoDS_Face& F, static_cast(n->GetPosition().get()); uv.SetCoord(fpos->GetUParameter(),fpos->GetVParameter()); if ( check ) - uvOK = CheckNodeUV( F, n, uv.ChangeCoord(), BRep_Tool::Tolerance( F )); + uvOK = CheckNodeUV( F, n, uv.ChangeCoord(), 10*MaxTolerance( F )); } else if(Pos->GetTypeOfPosition()==SMDS_TOP_EDGE) { @@ -375,12 +382,12 @@ gp_XY SMESH_MesherHelper::GetNodeUV(const TopoDS_Face& F, else uv.SetCoord(0.,0.); if ( check || !validU ) - uvOK = CheckNodeUV( F, n, uv.ChangeCoord(), BRep_Tool::Tolerance( E ),/*force=*/ !validU ); + uvOK = CheckNodeUV( F, n, uv.ChangeCoord(), 10*MaxTolerance( F ),/*force=*/ !validU ); // for a node on a seam edge select one of UVs on 2 pcurves if ( n2 && IsSeamShape( edgeID ) ) { - uv = GetUVOnSeam( uv, GetNodeUV( F, n2, 0 )); + uv = GetUVOnSeam( uv, GetNodeUV( F, n2, 0, check )); } else { // adjust uv to period @@ -491,12 +498,12 @@ bool SMESH_MesherHelper::CheckNodeUV(const TopoDS_Face& F, } Quantity_Parameter U,V; projector.LowerDistanceParameters(U,V); + uv.SetCoord( U,V ); if ( nodePnt.Distance( surface->Value( U, V )) > tol ) { MESSAGE( "SMESH_MesherHelper::CheckNodeUV(), invalid projection" ); return false; } - uv.SetCoord( U,V ); } else if ( uv.Modulus() > numeric_limits::min() ) { @@ -517,8 +524,8 @@ GeomAPI_ProjectPointOnSurf& SMESH_MesherHelper::GetProjector(const TopoDS_Face& { Handle(Geom_Surface) surface = BRep_Tool::Surface( F,loc ); int faceID = GetMeshDS()->ShapeToIndex( F ); - TID2Projector& i2proj = const_cast< TID2Projector&>( myFace2Projector ); - TID2Projector::iterator i_proj = i2proj.find( faceID ); + TID2ProjectorOnSurf& i2proj = const_cast< TID2ProjectorOnSurf&>( myFace2Projector ); + TID2ProjectorOnSurf::iterator i_proj = i2proj.find( faceID ); if ( i_proj == i2proj.end() ) { if ( tol == 0 ) tol = BRep_Tool::Tolerance( F ); @@ -632,7 +639,7 @@ double SMESH_MesherHelper::GetNodeU(const TopoDS_Edge& E, if ( !force && pos->GetTypeOfPosition()==SMDS_TOP_EDGE ) force = ( GetMeshDS()->ShapeToIndex( E ) != pos->GetShapeId() ); - *check = CheckNodeU( E, n, param, tol, force ); + *check = CheckNodeU( E, n, param, 2*tol, force ); } return param; } @@ -647,7 +654,8 @@ bool SMESH_MesherHelper::CheckNodeU(const TopoDS_Edge& E, const SMDS_MeshNode* n, double& u, const double tol, - const bool force) const + const bool force, + double* distance) const { if ( force || !myOkNodePosShapes.count( n->GetPosition()->GetShapeId() )) { @@ -666,22 +674,37 @@ bool SMESH_MesherHelper::CheckNodeU(const TopoDS_Edge& E, { gp_Pnt nodePnt = SMESH_MeshEditor::TNodeXYZ( n ); if ( !loc.IsIdentity() ) nodePnt.Transform( loc.Transformation().Inverted() ); - if ( nodePnt.Distance( curve->Value( u )) > tol ) + double dist = nodePnt.Distance( curve->Value( u )); + if ( distance ) *distance = dist; + if ( dist > tol ) { // u incorrect, project the node to the curve - GeomAPI_ProjectPointOnCurve projector( nodePnt, curve, f, l ); - if ( projector.NbPoints() < 1 ) + int edgeID = GetMeshDS()->ShapeToIndex( E ); + TID2ProjectorOnCurve& i2proj = const_cast< TID2ProjectorOnCurve&>( myEdge2Projector ); + TID2ProjectorOnCurve::iterator i_proj = + i2proj.insert( make_pair( edgeID, (GeomAPI_ProjectPointOnCurve*) 0 )).first; + if ( !i_proj->second ) + { + i_proj->second = new GeomAPI_ProjectPointOnCurve(); + i_proj->second->Init( curve, f, l ); + } + GeomAPI_ProjectPointOnCurve* projector = i_proj->second; + projector->Perform( nodePnt ); + if ( projector->NbPoints() < 1 ) { MESSAGE( "SMESH_MesherHelper::CheckNodeU() failed to project" ); return false; } - Quantity_Parameter U = projector.LowerDistanceParameter(); - if ( nodePnt.Distance( curve->Value( U )) > tol ) + Quantity_Parameter U = projector->LowerDistanceParameter(); + u = double( U ); + dist = nodePnt.Distance( curve->Value( U )); + if ( distance ) *distance = dist; + if ( dist > tol ) { MESSAGE( "SMESH_MesherHelper::CheckNodeU(), invalid projection" ); return false; } - u = double( U ); + //u = double( U ); } else if ( fabs( u ) > numeric_limits::min() ) { @@ -767,6 +790,11 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1, } else if (edgeID>0 || shapeType == TopAbs_EDGE) { + if ( Pos1->GetTypeOfPosition()==SMDS_TOP_EDGE && + Pos2->GetTypeOfPosition()==SMDS_TOP_EDGE && + Pos1->GetShapeId() != Pos2->GetShapeId() ) // issue 0021006 + return getMediumNodeOnComposedWire(n1,n2,force3d); + if( myShape.IsNull() ) E = TopoDS::Edge(meshDS->IndexToShape(edgeID)); else { @@ -834,16 +862,16 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1, if ( !F.IsNull() ) { gp_XY UV = ( uv[0] + uv[1] ) / 2.; - CheckNodeUV( F, n12, UV, BRep_Tool::Tolerance( F ), /*force=*/true); + CheckNodeUV( F, n12, UV, 2*BRep_Tool::Tolerance( F ), /*force=*/true); meshDS->SetNodeOnFace(n12, faceID, UV.X(), UV.Y() ); } else if ( !E.IsNull() ) { double U = ( u[0] + u[1] ) / 2.; - CheckNodeU( E, n12, U, BRep_Tool::Tolerance( E ), /*force=*/true); + CheckNodeU( E, n12, U, 2*BRep_Tool::Tolerance( E ), /*force=*/true); meshDS->SetNodeOnEdge(n12, edgeID, U); } - else if ( myShapeID > 1 ) + else if ( myShapeID > 0 ) { meshDS->SetNodeInVolume(n12, myShapeID); } @@ -851,6 +879,78 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1, return n12; } +//================================================================================ +/*! + * \brief Makes a medium node if nodes reside different edges + */ +//================================================================================ + +const SMDS_MeshNode* SMESH_MesherHelper::getMediumNodeOnComposedWire(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + bool force3d) +{ + gp_Pnt middle = 0.5 * XYZ(n1) + 0.5 * XYZ(n2); + SMDS_MeshNode* n12 = AddNode( middle.X(), middle.Y(), middle.Z() ); + + // To find position on edge and 3D position for n12, + // project to 2 edges and select projection most close to + + double u = 0, distMiddleProj = Precision::Infinite(); + int iOkEdge = 0; + TopoDS_Edge edges[2]; + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + // get an edge + const SMDS_MeshNode* n = is2nd ? n2 : n1; + TopoDS_Shape shape = GetSubShapeByNode( n, GetMeshDS() ); + if ( shape.IsNull() || shape.ShapeType() != TopAbs_EDGE ) + continue; + + // project to get U of projection and distance from middle to projection + TopoDS_Edge edge = edges[ is2nd ] = TopoDS::Edge( shape ); + double node2MiddleDist = middle.Distance( XYZ(n) ); + double foundU = GetNodeU( edge, n ), foundDist = node2MiddleDist; + CheckNodeU( edge, n12, foundU, 2*BRep_Tool::Tolerance(edge), /*force=*/true, &foundDist ); + if ( foundDist < node2MiddleDist ) + { + distMiddleProj = foundDist; + u = foundU; + iOkEdge = is2nd; + } + } + if ( Precision::IsInfinite( distMiddleProj )) + { + // both projections failed; set n12 on the edge of n1 with U of a common vertex + TopoDS_Vertex vCommon; + if ( TopExp::CommonVertex( edges[0], edges[1], vCommon )) + u = BRep_Tool::Parameter( vCommon, edges[0] ); + else + { + double f,l, u0 = GetNodeU( edges[0], n1 ); + BRep_Tool::Range( edges[0],f,l ); + u = ( fabs(u0-f) < fabs(u0-l) ) ? f : l; + } + iOkEdge = 0; + distMiddleProj = 0; + } + + // move n12 to position of a successfull projection + double tol = BRep_Tool::Tolerance(edges[ iOkEdge ]); + if ( !force3d && distMiddleProj > 2*tol ) + { + TopLoc_Location loc; double f,l; + Handle(Geom_Curve) curve = BRep_Tool::Curve( edges[iOkEdge],loc,f,l ); + gp_Pnt p = curve->Value( u ); + GetMeshDS()->MoveNode( n12, p.X(), p.Y(), p.Z() ); + } + + GetMeshDS()->SetNodeOnEdge(n12, edges[iOkEdge], u); + + myTLinkNodeMap.insert( make_pair( SMESH_TLink(n1,n2), n12 )); + + return n12; +} + //======================================================================= //function : AddNode //purpose : Creates a node @@ -1006,6 +1106,45 @@ SMDS_MeshFace* SMESH_MesherHelper::AddFace(const SMDS_MeshNode* n1, return elem; } +//======================================================================= +//function : AddPolygonalFace +//purpose : Creates polygon, with additional nodes in quadratic mesh +//======================================================================= + +SMDS_MeshFace* SMESH_MesherHelper::AddPolygonalFace (const vector& nodes, + const int id, + const bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshFace* elem = 0; + + if(!myCreateQuadratic) { + if(id) + elem = meshDS->AddPolygonalFaceWithID(nodes, id); + else + elem = meshDS->AddPolygonalFace(nodes); + } + else { + vector newNodes; + for ( int i = 0; i < nodes.size(); ++i ) + { + const SMDS_MeshNode* n1 = nodes[i]; + const SMDS_MeshNode* n2 = nodes[(i+1)/nodes.size()]; + const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); + newNodes.push_back( n1 ); + newNodes.push_back( n12 ); + } + if(id) + elem = meshDS->AddPolygonalFaceWithID(newNodes, id); + else + elem = meshDS->AddPolygonalFace(newNodes); + } + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( elem, myShapeID ); + + return elem; +} + //======================================================================= //function : AddVolume //purpose : Creates quadratic or linear prism @@ -1196,6 +1335,62 @@ SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1, return elem; } +//======================================================================= +//function : AddPolyhedralVolume +//purpose : Creates polyhedron. In quadratic mesh, adds medium nodes +//======================================================================= + +SMDS_MeshVolume* +SMESH_MesherHelper::AddPolyhedralVolume (const std::vector& nodes, + const std::vector& quantities, + const int id, + const bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshVolume* elem = 0; + if(!myCreateQuadratic) + { + if(id) + elem = meshDS->AddPolyhedralVolumeWithID(nodes, quantities, id); + else + elem = meshDS->AddPolyhedralVolume(nodes, quantities); + } + else + { + vector newNodes; + vector newQuantities; + for ( int iFace=0, iN=0; iFace < quantities.size(); ++iFace) + { + int nbNodesInFace = quantities[iFace]; + newQuantities.push_back(0); + for ( int i = 0; i < nbNodesInFace; ++i ) + { + const SMDS_MeshNode* n1 = nodes[ iN + i ]; + newNodes.push_back( n1 ); + newQuantities.back()++; + + const SMDS_MeshNode* n2 = nodes[ iN + ( i+1==nbNodesInFace ? 0 : i+1 )]; +// if ( n1->GetPosition()->GetTypeOfPosition() != SMDS_TOP_3DSPACE && +// n2->GetPosition()->GetTypeOfPosition() != SMDS_TOP_3DSPACE ) + { + const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); + newNodes.push_back( n12 ); + newQuantities.back()++; + } + } + iN += nbNodesInFace; + } + if(id) + elem = meshDS->AddPolyhedralVolumeWithID( newNodes, newQuantities, id ); + else + elem = meshDS->AddPolyhedralVolume( newNodes, newQuantities ); + } + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( elem, myShapeID ); + + return elem; +} + //======================================================================= //function : LoadNodeColumns //purpose : Load nodes bound to face into a map of node columns @@ -1343,6 +1538,26 @@ bool SMESH_MesherHelper::IsSubShape( const TopoDS_Shape& shape, SMESH_Mesh* aMes shape.ShapeType() == TopAbs_COMPOUND && aMesh->GetMeshDS()->IsGroupOfSubShapes( shape ); } +//================================================================================ +/*! + * \brief Return maximal tolerance of shape + */ +//================================================================================ + +double SMESH_MesherHelper::MaxTolerance( const TopoDS_Shape& shape ) +{ + double tol = Precision::Confusion(); + TopExp_Explorer exp; + for ( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() ) + tol = Max( tol, BRep_Tool::Tolerance( TopoDS::Face( exp.Current()))); + for ( exp.Init( shape, TopAbs_EDGE ); exp.More(); exp.Next() ) + tol = Max( tol, BRep_Tool::Tolerance( TopoDS::Edge( exp.Current()))); + for ( exp.Init( shape, TopAbs_VERTEX ); exp.More(); exp.Next() ) + tol = Max( tol, BRep_Tool::Tolerance( TopoDS::Vertex( exp.Current()))); + + return tol; +} + //======================================================================= //function : IsQuadraticMesh //purpose : Check mesh without geometry for: if all elements on this shape are quadratic, @@ -1388,16 +1603,23 @@ double SMESH_MesherHelper::GetOtherParam(const double param) const return fabs(param-myPar1[i]) < fabs(param-myPar2[i]) ? myPar2[i] : myPar1[i]; } +//#include + //======================================================================= namespace { // Structures used by FixQuadraticElements() //======================================================================= #define __DMP__(txt) \ -//cout << txt + //cout << txt #define MSG(txt) __DMP__(txt< < 1/15 * + return middleNodeMove2 < 1/15./15. * linkLen2; + } struct QFace; // --------------------------------------- @@ -1434,8 +1656,10 @@ namespace { // Structures used by FixQuadraticElements() { _nodeMove += move; _nbMoves += sum ? (_nbMoves==0) : 1; } gp_XYZ Move() const { return _nodeMove.XYZ() / _nbMoves; } bool IsMoved() const { return (_nbMoves > 0 && !IsStraight()); } - bool IsStraight() const { return _nodeMove.SquareMagnitude() <= straightTol2; } - + bool IsStraight() const + { return isStraightLink( (XYZ(node1())-XYZ(node2())).SquareModulus(), + _nodeMove.SquareMagnitude()); + } bool operator<(const QLink& other) const { return (node1()->GetID() == other.node1()->GetID() ? node2()->GetID() < other.node2()->GetID() : @@ -1457,7 +1681,7 @@ namespace { // Structures used by FixQuadraticElements() TChainLink(const QLink* qlink=0):_qlink(qlink) { _qfaces[0] = _qfaces[1] = 0; } - void SetFace(const QFace* face) { int iF = _qfaces[0] ? 1 : 0; _qfaces[iF]=face; } + void SetFace(const QFace* face) const { int iF = _qfaces[0] ? 1 : 0; _qfaces[iF]=face; } bool IsBoundary() const { return !_qfaces[1]; } @@ -1616,7 +1840,7 @@ namespace { // Structures used by FixQuadraticElements() } //================================================================================ /*! - * \brief Make up chain of links + * \brief Make up a chain of links * \param iSide - link to add first * \param chain - chain to fill in * \param pos - postion of medium nodes the links should have @@ -1635,22 +1859,33 @@ namespace { // Structures used by FixQuadraticElements() if ( _sides.size() != 4 ) { // triangle - visit all my continous faces MSGBEG( *this ); + TLinkSet links; list< const QFace* > faces( 1, this ); - for (list< const QFace* >::iterator fIt = faces.begin(); fIt != faces.end(); ++fIt ) { - const QFace* face = *fIt; + while ( !faces.empty() ) { + const QFace* face = faces.front(); for ( int i = 0; i < face->_sides.size(); ++i ) { if ( !face->_sideIsAdded[i] && face->_sides[i] ) { face->_sideIsAdded[i] = true; - TChain::iterator chLink = chain.insert( chain.begin(), TChainLink(face->_sides[i])); + // find a face side in the chain + TLinkInSet chLink = links.insert( TChainLink(face->_sides[i])).first; +// TChain::iterator chLink = chain.begin(); +// for ( ; chLink != chain.end(); ++chLink ) +// if ( chLink->_qlink == face->_sides[i] ) +// break; +// if ( chLink == chain.end() ) +// chLink = chain.insert( chain.begin(), TChainLink(face->_sides[i])); + // add a face to a chained link and put a continues face in the queue chLink->SetFace( face ); if ( face->_sides[i]->MediumPos() >= pos ) if ( const QFace* contFace = face->_sides[i]->GetContinuesFace( face )) faces.push_back( contFace ); } } + faces.pop_front(); } if ( error < ERR_TRI ) error = ERR_TRI; + chain.insert( chain.end(), links.begin(),links.end() ); return false; } _sideIsAdded[iSide] = true; // not to add this link to chain again @@ -1716,7 +1951,7 @@ namespace { // Structures used by FixQuadraticElements() TLinkInSet link = links.find( _sides[iL] ); if ( link == linksEnd ) continue; if ( (*link)->MediumPos() > SMDS_TOP_FACE ) - continue; // We work on faces here, don't go into a volume + continue; // We work on faces here, don't go inside a solid // check link if ( link->IsBoundary() ) { @@ -1859,7 +2094,8 @@ namespace { // Structures used by FixQuadraticElements() // propagate to adjacent faces till limit step or boundary double len1 = thePrevLen + (theLink->MiddlePnt() - _sides[iL1]->MiddlePnt()).Modulus(); double len2 = thePrevLen + (theLink->MiddlePnt() - _sides[iL2]->MiddlePnt()).Modulus(); - gp_Vec linkDir1, linkDir2; + gp_Vec linkDir1(0,0,0); // initialize to avoid valgrind error ("Conditional jump...") + gp_Vec linkDir2(0,0,0); try { OCC_CATCH_SIGNALS; if ( f1 ) @@ -2095,7 +2331,7 @@ namespace { // Structures used by FixQuadraticElements() enum TSplitTriaResult { _OK, _NO_CORNERS, _FEW_ROWS, _MANY_ROWS, _NO_SIDELINK, _BAD_MIDQUAD, _NOT_RECT, - _NO_MIDQUAD, _NO_UPTRIA, _BAD_SET_SIZE, _BAD_CORNER, _BAD_START, _NO_BOTLINK }; + _NO_MIDQUAD, _NO_UPTRIA, _BAD_SET_SIZE, _BAD_CORNER, _BAD_START, _NO_BOTLINK, _TWISTED_CHAIN }; TSplitTriaResult splitTrianglesIntoChains( TChain & allLinks, vector< TChain> & resultChains, @@ -2161,6 +2397,8 @@ namespace { // Structures used by FixQuadraticElements() const QFace* botTria = botLink->_qfaces[0]; // bottom triangle bound by botLink if ( !botTria ) { // the column ends + if ( botLink == startLink ) + return _TWISTED_CHAIN; // issue 0020951 linkSet.erase( botLink ); if ( iRow != rowChains.size() ) return _FEW_ROWS; // different nb of rows in columns @@ -2220,8 +2458,10 @@ namespace { // Structures used by FixQuadraticElements() // next bottom link ends at the new corner linkSet.erase( botLink ); botLink = upTria->GetLinkByNode( linkSet, (isCase2 ? *sideLink : *midQuadLink), corner ); - if ( botLink == linksEnd || botLink == (isCase2 ? midQuadLink : sideLink)) + if ( botLink == linksEnd || botLink == midQuadLink || botLink == sideLink) return _NO_BOTLINK; + if ( midQuadLink == startLink || sideLink == startLink ) + return _TWISTED_CHAIN; // issue 0020951 linkSet.erase( midQuadLink ); linkSet.erase( sideLink ); @@ -2265,7 +2505,7 @@ namespace { // Structures used by FixQuadraticElements() return _OK; } -} +} //namespace //======================================================================= /*! @@ -2278,37 +2518,49 @@ namespace { // Structures used by FixQuadraticElements() void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) { - // apply algorithm to solids or geom faces + // 0. Apply algorithm to solids or geom faces // ---------------------------------------------- if ( myShape.IsNull() ) { if ( !myMesh->HasShapeToMesh() ) return; SetSubShape( myMesh->GetShapeToMesh() ); +#ifdef _DEBUG_ + int nbSolids = 0; + TopTools_IndexedMapOfShape solids; + TopExp::MapShapes(myShape,TopAbs_SOLID,solids); + nbSolids = solids.Extent(); +#endif TopTools_MapOfShape faces; // faces not in solid or in not meshed solid for ( TopExp_Explorer f(myShape,TopAbs_FACE,TopAbs_SOLID); f.More(); f.Next() ) { - faces.Add( f.Current() ); + faces.Add( f.Current() ); // not in solid } for ( TopExp_Explorer s(myShape,TopAbs_SOLID); s.More(); s.Next() ) { if ( myMesh->GetSubMesh( s.Current() )->IsEmpty() ) { // get faces of solid for ( TopExp_Explorer f( s.Current(), TopAbs_FACE); f.More(); f.Next() ) - faces.Add( f.Current() ); + faces.Add( f.Current() ); // in not meshed solid } else { // fix nodes in the solid and its faces + MSG("FIX SOLID " << nbSolids-- << " #" << GetMeshDS()->ShapeToIndex(s.Current())); SMESH_MesherHelper h(*myMesh); h.SetSubShape( s.Current() ); h.FixQuadraticElements(false); } } // fix nodes on geom faces +#ifdef _DEBUG_ + int nbfaces = faces.Extent(); +#endif for ( TopTools_MapIteratorOfMapOfShape fIt( faces ); fIt.More(); fIt.Next() ) { + MSG("FIX FACE " << nbfaces-- << " #" << GetMeshDS()->ShapeToIndex(fIt.Key())); SMESH_MesherHelper h(*myMesh); h.SetSubShape( fIt.Key() ); h.FixQuadraticElements(true); } + //perf_print_all_meters(1); return; } - // Find out type of elements and get iterator on them + // 1. Find out type of elements and get iterator on them // --------------------------------------------------- SMDS_ElemIteratorPtr elemIt; @@ -2327,7 +2579,7 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) if ( !elemIt || !elemIt->more() || elemType < SMDSAbs_Face ) return; - // Fill in auxiliary data structures + // 2. Fill in auxiliary data structures // ---------------------------------- set< QLink > links; @@ -2336,7 +2588,7 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) set< QFace >::iterator pFace; bool isCurved = false; - bool hasRectFaces = false; + //bool hasRectFaces = false; set nbElemNodeSet; if ( elemType == SMDSAbs_Volume ) @@ -2369,9 +2621,9 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) if ( pFace->NbVolumes() == 0 ) pFace->AddSelfToLinks(); pFace->SetVolume( vol ); - hasRectFaces = hasRectFaces || - ( volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_HEXA || - volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_PENTA ); +// hasRectFaces = hasRectFaces || +// ( volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_HEXA || +// volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_PENTA ); #ifdef _DEBUG_ if ( nbN == 6 ) pFace->_face = GetMeshDS()->FindFace(faceNodes[0],faceNodes[2],faceNodes[4]); @@ -2407,13 +2659,13 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) // store QFace pFace = faces.insert( QFace( faceLinks )).first; pFace->AddSelfToLinks(); - hasRectFaces = ( hasRectFaces || nbN == 4 ); + //hasRectFaces = ( hasRectFaces || nbN == 4 ); } } if ( !isCurved ) return; // no curved edges of faces - // Compute displacement of medium nodes + // 3. Compute displacement of medium nodes // ------------------------------------- // two loops on faces: the first is to treat boundary links, the second is for internal ones @@ -2423,6 +2675,7 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) for ( ; isInside < 2; ++isInside ) { MSG( "--------------- LOOP (inside=" << isInside << ") ------------------"); SMDS_TypeOfPosition pos = isInside ? SMDS_TOP_3DSPACE : SMDS_TOP_FACE; + SMDS_TypeOfPosition bndPos = isInside ? SMDS_TOP_FACE : SMDS_TOP_EDGE; for ( pFace = faces.begin(); pFace != faces.end(); ++pFace ) { if ( bool(isInside) == pFace->IsBoundary() ) @@ -2461,7 +2714,12 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) TChain& chain = chains[iC]; if ( chain.empty() ) continue; if ( chain.front()->IsStraight() && chain.back()->IsStraight() ) { - MSG("3D straight"); + MSG("3D straight - ignore"); + continue; + } + if ( chain.front()->MediumPos() > bndPos || + chain.back()->MediumPos() > bndPos ) { + MSG("Internal chain - ignore"); continue; } // mesure chain length and compute link position along the chain @@ -2498,6 +2756,7 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) { face = TopoDS::Face( f ); Handle(Geom_Surface) surf = BRep_Tool::Surface(face,loc); + bool isStraight[2]; for ( int is1 = 0; is1 < 2; ++is1 ) // move0 or move1 { TChainLink& link = is1 ? chain.back() : chain.front(); @@ -2508,10 +2767,14 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) // uvMove = uvm - uv12 gp_XY uvMove = applyIn2D(surf, uvm, uv12, gp_XY_Subtracted, /*inPeriod=*/false); ( is1 ? move1 : move0 ).SetCoord( uvMove.X(), uvMove.Y(), 0 ); + if ( !is1 ) // correct nodeOnFace for move1 (issue 0020919) + nodeOnFace = (*(++chain.rbegin()))->_mediumNode; + isStraight[is1] = isStraightLink( (uv2-uv1).SquareModulus(),uvMove.SquareModulus()); } - if ( move0.SquareMagnitude() < straightTol2 && - move1.SquareMagnitude() < straightTol2 ) { - MSG("2D straight"); +// if ( move0.SquareMagnitude() < straightTol2 && +// move1.SquareMagnitude() < straightTol2 ) { + if ( isStraight[0] && isStraight[1] ) { + MSG("2D straight - ignore"); continue; // straight - no need to move nodes of internal links } } @@ -2563,7 +2826,8 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) { gp_XY uv0 = GetNodeUV( face, (*link0)->_mediumNode, 0, &checkUV); gp_XY uv2 = GetNodeUV( face, (*link2)->_mediumNode, 0, &checkUV); - MSG( "uv0: "< #include +#include class GeomAPI_ProjectPointOnSurf; +class GeomAPI_ProjectPointOnCurve; typedef std::map TLinkNodeMap; typedef std::map::iterator ItTLinkNode; @@ -139,6 +141,8 @@ public: static bool IsSubShape( const TopoDS_Shape& shape, SMESH_Mesh* aMesh ); + static double MaxTolerance( const TopoDS_Shape& shape ); + public: // ---------- PUBLIC INSTANCE METHODS ---------- @@ -221,8 +225,15 @@ public: const SMDS_MeshNode* n4, const int id = 0, const bool force3d = false); + + /*! + * Creates polygon, with additional nodes in quadratic mesh + */ + SMDS_MeshFace* AddPolygonalFace (const std::vector& nodes, + const int id = 0, + const bool force3d = false); /*! - * Creates quadratic or linear tetraahedron + * Creates quadratic or linear tetrahedron */ SMDS_MeshVolume* AddVolume(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, @@ -264,6 +275,14 @@ public: const SMDS_MeshNode* n8, const int id = 0, bool force3d = true); + + /*! + * Creates polyhedron. In quadratic mesh, adds medium nodes + */ + SMDS_MeshVolume* AddPolyhedralVolume (const std::vector& nodes, + const std::vector& quantities, + const int ID=0, + const bool force3d = true); /*! * \brief Return U of the given node on the edge */ @@ -298,7 +317,8 @@ public: const SMDS_MeshNode* n, double& u, const double tol, - const bool force=false) const; + const bool force=false, + double* distance=0) const; /*! * \brief Return middle UV taking in account surface period */ @@ -453,6 +473,9 @@ protected: */ gp_Pnt2d GetUVOnSeam( const gp_Pnt2d& uv1, const gp_Pnt2d& uv2 ) const; + const SMDS_MeshNode* getMediumNodeOnComposedWire(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + bool force3d); private: // Forbiden copy constructor @@ -466,8 +489,10 @@ protected: double myPar1[2], myPar2[2]; // U and V bounds of a closed periodic surface int myParIndex; // bounds' index (1-U, 2-V, 3-both) - typedef std::map< int, GeomAPI_ProjectPointOnSurf* > TID2Projector; - TID2Projector myFace2Projector; + typedef std::map< int, GeomAPI_ProjectPointOnSurf* > TID2ProjectorOnSurf; + TID2ProjectorOnSurf myFace2Projector; + typedef std::map< int, GeomAPI_ProjectPointOnCurve* > TID2ProjectorOnCurve; + TID2ProjectorOnCurve myEdge2Projector; TopoDS_Shape myShape; SMESH_Mesh* myMesh; diff --git a/src/SMESH/SMESH_OctreeNode.cxx b/src/SMESH/SMESH_OctreeNode.cxx index 37a7d4f1b..7cfe10d11 100644 --- a/src/SMESH/SMESH_OctreeNode.cxx +++ b/src/SMESH/SMESH_OctreeNode.cxx @@ -29,7 +29,6 @@ // #include "SMESH_OctreeNode.hxx" -#include "SMDS_MeshNode.hxx" #include "SMDS_SetIterator.hxx" #include @@ -44,7 +43,7 @@ using namespace std; * \param minBoxSize - Minimal size of the Octree Box */ //================================================================ -SMESH_OctreeNode::SMESH_OctreeNode (const set & theNodes, const int maxLevel, +SMESH_OctreeNode::SMESH_OctreeNode (const TIDSortedNodeSet & theNodes, const int maxLevel, const int maxNbNodes , const double minBoxSize ) :SMESH_Octree( new SMESH_Octree::Limit( maxLevel,minBoxSize)), myMaxNbNodes(maxNbNodes), @@ -86,7 +85,7 @@ SMESH_Octree* SMESH_OctreeNode::allocateOctreeChild() const Bnd_B3d* SMESH_OctreeNode::buildRootBox() { Bnd_B3d* box = new Bnd_B3d; - set::iterator it = myNodes.begin(); + TIDSortedNodeSet::iterator it = myNodes.begin(); for (; it != myNodes.end(); it++) { const SMDS_MeshNode* n1 = *it; gp_XYZ p1( n1->X(), n1->Y(), n1->Z() ); @@ -129,7 +128,7 @@ void SMESH_OctreeNode::buildChildrenData() gp_XYZ max = getBox().CornerMax(); gp_XYZ mid = (min + max)/2.; - set::iterator it = myNodes.begin(); + TIDSortedNodeSet::iterator it = myNodes.begin(); while (it != myNodes.end()) { const SMDS_MeshNode* n1 = *it; @@ -214,7 +213,7 @@ bool SMESH_OctreeNode::NodesAround(const SMDS_MeshNode * node, { double minDist = precision * precision; gp_Pnt p1 ( node->X(), node->Y(), node->Z() ); - set::iterator nIt = myNodes.begin(); + TIDSortedNodeSet::iterator nIt = myNodes.begin(); for ( ; nIt != myNodes.end(); ++nIt ) { gp_Pnt p2 ( (*nIt)->X(), (*nIt)->Y(), (*nIt)->Z() ); @@ -243,7 +242,7 @@ bool SMESH_OctreeNode::NodesAround(const SMDS_MeshNode * node, * \param maxNbNodes - maximum Nodes in a Leaf of the SMESH_OctreeNode constructed, default value is 5 */ //============================= -void SMESH_OctreeNode::FindCoincidentNodes (set& theSetOfNodes, +void SMESH_OctreeNode::FindCoincidentNodes (TIDSortedNodeSet& theSetOfNodes, list< list< const SMDS_MeshNode*> >* theGroupsOfNodes, const double theTolerance, const int maxLevel, @@ -263,11 +262,11 @@ void SMESH_OctreeNode::FindCoincidentNodes (set& theSetOfN * \param theGroupsOfNodes - list of nodes closed to each other returned */ //============================= -void SMESH_OctreeNode::FindCoincidentNodes ( set* theSetOfNodes, +void SMESH_OctreeNode::FindCoincidentNodes ( TIDSortedNodeSet* theSetOfNodes, const double theTolerance, list< list< const SMDS_MeshNode*> >* theGroupsOfNodes) { - set::iterator it1 = theSetOfNodes->begin(); + TIDSortedNodeSet::iterator it1 = theSetOfNodes->begin(); list::iterator it2; while (it1 != theSetOfNodes->end()) @@ -316,7 +315,7 @@ void SMESH_OctreeNode::FindCoincidentNodes ( set* theSetOf */ //====================================================================================== void SMESH_OctreeNode::FindCoincidentNodes (const SMDS_MeshNode * Node, - set* SetOfNodes, + TIDSortedNodeSet* SetOfNodes, list* Result, const double precision) { @@ -329,8 +328,8 @@ void SMESH_OctreeNode::FindCoincidentNodes (const SMDS_MeshNode * Node, { gp_Pnt p1 (Node->X(), Node->Y(), Node->Z()); - set myNodesCopy = myNodes; - set::iterator it = myNodesCopy.begin(); + TIDSortedNodeSet myNodesCopy = myNodes; + TIDSortedNodeSet::iterator it = myNodesCopy.begin(); double tol2 = precision * precision; bool squareBool; @@ -383,7 +382,7 @@ void SMESH_OctreeNode::UpdateByMoveNode( const SMDS_MeshNode* node, const gp_Pnt { if ( isLeaf() ) { - set::iterator pNode = myNodes.find( node ); + TIDSortedNodeSet::iterator pNode = myNodes.find( node ); bool nodeInMe = ( pNode != myNodes.end() ); SMDS_MeshNode pointNode( toPnt.X(), toPnt.Y(), toPnt.Z() ); @@ -430,6 +429,6 @@ SMESH_OctreeNodeIteratorPtr SMESH_OctreeNode::GetChildrenIterator() SMDS_NodeIteratorPtr SMESH_OctreeNode::GetNodeIterator() { return SMDS_NodeIteratorPtr - ( new SMDS_SetIterator< SMDS_pNode, set< SMDS_pNode >::const_iterator > + ( new SMDS_SetIterator< SMDS_pNode, TIDSortedNodeSet::const_iterator > ( myNodes.begin(), myNodes.size() ? myNodes.end() : myNodes.begin())); } diff --git a/src/SMESH/SMESH_OctreeNode.hxx b/src/SMESH/SMESH_OctreeNode.hxx index f5e3fbf52..951d2bc14 100644 --- a/src/SMESH/SMESH_OctreeNode.hxx +++ b/src/SMESH/SMESH_OctreeNode.hxx @@ -31,6 +31,7 @@ #define _SMESH_OCTREENODE_HXX_ #include "SMESH_Octree.hxx" +#include "SMDS_MeshNode.hxx" #include #include @@ -42,15 +43,16 @@ class SMDS_MeshNode; class SMESH_OctreeNode; -typedef SMDS_Iterator SMESH_OctreeNodeIterator; -typedef boost::shared_ptr SMESH_OctreeNodeIteratorPtr; +typedef SMDS_Iterator SMESH_OctreeNodeIterator; +typedef boost::shared_ptr SMESH_OctreeNodeIteratorPtr; +typedef std::set< const SMDS_MeshNode*, TIDCompare > TIDSortedNodeSet; class SMESH_OctreeNode : public SMESH_Octree { public: // Constructor - SMESH_OctreeNode (const std::set& theNodes, const int maxLevel = 8, + SMESH_OctreeNode (const TIDSortedNodeSet& theNodes, const int maxLevel = 8, const int maxNbNodes = 5, const double minBoxSize = 0.); //============================= @@ -64,9 +66,9 @@ public: virtual const bool isInside(const SMDS_MeshNode * Node, const double precision = 0.); // Return in Result a list of Nodes potentials to be near Node - void NodesAround(const SMDS_MeshNode * Node, + void NodesAround(const SMDS_MeshNode * Node, std::list* Result, - const double precision = 0.); + const double precision = 0.); // Return in dist2Nodes nodes mapped to their square distance from Node bool NodesAround(const SMDS_MeshNode * Node, @@ -75,13 +77,13 @@ public: // Return in theGroupsOfNodes a list of group of nodes close to each other within theTolerance // Search for all the nodes in nodes - void FindCoincidentNodes ( std::set* nodes, + void FindCoincidentNodes ( TIDSortedNodeSet* nodes, const double theTolerance, std::list< std::list< const SMDS_MeshNode*> >* theGroupsOfNodes); // Static method that return in theGroupsOfNodes a list of group of nodes close to each other within // theTolerance search for all the nodes in nodes - static void FindCoincidentNodes ( std::set& nodes, + static void FindCoincidentNodes ( TIDSortedNodeSet& nodes, std::list< std::list< const SMDS_MeshNode*> >* theGroupsOfNodes, const double theTolerance = 0.00001, const int maxLevel = -1, @@ -117,16 +119,16 @@ protected: virtual SMESH_Octree* allocateOctreeChild() const; // Return in result a list of nodes closed to Node and remove it from SetOfNodes - void FindCoincidentNodes( const SMDS_MeshNode * Node, - std::set* SetOfNodes, + void FindCoincidentNodes( const SMDS_MeshNode * Node, + TIDSortedNodeSet* SetOfNodes, std::list* Result, - const double precision); + const double precision); // The max number of nodes a leaf box can contain - int myMaxNbNodes; + int myMaxNbNodes; // The set of nodes inside the box of the Octree (Empty if Octree is not a leaf) - std::set myNodes; + TIDSortedNodeSet myNodes; }; diff --git a/src/SMESH/SMESH_Pattern.cxx b/src/SMESH/SMESH_Pattern.cxx index 43ee8669d..0857f545d 100644 --- a/src/SMESH/SMESH_Pattern.cxx +++ b/src/SMESH/SMESH_Pattern.cxx @@ -766,7 +766,12 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, } paramNodeMap.insert( make_pair( u, node )); } - } + + //rnv : To fix the bug IPAL21999 Pattern Mapping - New - collapse of pattern mesh + if ( paramNodeMap.size() != eSubMesh->NbNodes() ) + return setErrorCode(ERR_UNEXPECTED); + } + // put U in [0,1] so that the first key-point has U==0 bool isSeam = helper.IsRealSeam( edge ); double du = l - f; diff --git a/src/SMESH/SMESH_Pattern.hxx b/src/SMESH/SMESH_Pattern.hxx index 4bac41585..e809ca195 100644 --- a/src/SMESH/SMESH_Pattern.hxx +++ b/src/SMESH/SMESH_Pattern.hxx @@ -191,7 +191,9 @@ class SMESH_EXPORT SMESH_Pattern { // Apply(mesh_face) ERR_APPLF_BAD_FACE_GEOM, // bad face geometry // MakeMesh - ERR_MAKEM_NOT_COMPUTED // mapping failed + ERR_MAKEM_NOT_COMPUTED, // mapping failed + //Unexpected error + ERR_UNEXPECTED // Unexpected of the pattern mapping alorithm }; ErrorCode GetErrorCode() const { return myErrorCode; } diff --git a/src/SMESH/SMESH_subMesh.cxx b/src/SMESH/SMESH_subMesh.cxx index 4d92816fc..69b33a94c 100644 --- a/src/SMESH/SMESH_subMesh.cxx +++ b/src/SMESH/SMESH_subMesh.cxx @@ -265,7 +265,7 @@ bool SMESH_subMesh::SubMeshesComputed() break; // the rest subMeshes are all of less dimension SMESHDS_SubMesh * ds = sm->GetSubMeshDS(); bool computeOk = (sm->GetComputeState() == COMPUTE_OK || - (ds && ( ds->NbNodes() || ds->NbElements() ))); + (ds && ( dimToCheck ? ds->NbElements() : ds->NbNodes() ))); if (!computeOk) { int type = ss.ShapeType(); @@ -372,23 +372,24 @@ const map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn() case TopAbs_COMPOUND: { //MESSAGE("compound"); - for (TopExp_Explorer exp(_subShape, TopAbs_SOLID); exp.More(); - exp.Next()) + for (TopExp_Explorer exp(_subShape, TopAbs_SOLID); exp.More();exp.Next()) { InsertDependence(exp.Current()); } - for (TopExp_Explorer exp(_subShape, TopAbs_SHELL, TopAbs_SOLID); exp.More(); - exp.Next()) + for (TopExp_Explorer exp(_subShape, TopAbs_SHELL, TopAbs_SOLID); exp.More(); exp.Next()) { + if ( BRep_Tool::IsClosed(exp.Current() )) InsertDependence(exp.Current()); //only shell not in solid + else + for (TopExp_Explorer expF(exp.Current(), TopAbs_FACE); expF.More();expF.Next()) + InsertDependence(expF.Current()); // issue 0020959: HEXA_3D fails on shell + } - for (TopExp_Explorer exp(_subShape, TopAbs_FACE, TopAbs_SHELL); exp.More(); - exp.Next()) + for (TopExp_Explorer exp(_subShape, TopAbs_FACE, TopAbs_SHELL); exp.More();exp.Next()) { InsertDependence(exp.Current()); } - for (TopExp_Explorer exp(_subShape, TopAbs_EDGE, TopAbs_FACE); exp.More(); - exp.Next()) + for (TopExp_Explorer exp(_subShape, TopAbs_EDGE, TopAbs_FACE); exp.More();exp.Next()) { InsertDependence(exp.Current()); } @@ -396,9 +397,8 @@ const map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn() } case TopAbs_COMPSOLID: { - //MESSAGE("compsolid"); - for (TopExp_Explorer exp(_subShape, TopAbs_SOLID); exp.More(); - exp.Next()) + //MESSAGE("compsolid"); + for (TopExp_Explorer exp(_subShape, TopAbs_SOLID); exp.More(); exp.Next()) { InsertDependence(exp.Current()); } @@ -407,8 +407,7 @@ const map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn() case TopAbs_SHELL: { //MESSAGE("shell"); - for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More(); - exp.Next()) + for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More(); exp.Next()) { InsertDependence(exp.Current()); } @@ -417,8 +416,7 @@ const map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn() case TopAbs_WIRE: { //MESSAGE("wire"); - for (TopExp_Explorer exp(_subShape, TopAbs_EDGE); exp.More(); - exp.Next()) + for (TopExp_Explorer exp(_subShape, TopAbs_EDGE); exp.More(); exp.Next()) { InsertDependence(exp.Current()); } @@ -428,8 +426,7 @@ const map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn() { //MESSAGE("solid"); if(_father->HasShapeToMesh()) { - for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More(); - exp.Next()) + for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More();exp.Next()) { InsertDependence(exp.Current()); } @@ -439,8 +436,7 @@ const map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn() case TopAbs_FACE: { //MESSAGE("face"); - for (TopExp_Explorer exp(_subShape, TopAbs_EDGE); exp.More(); - exp.Next()) + for (TopExp_Explorer exp(_subShape, TopAbs_EDGE); exp.More();exp.Next()) { InsertDependence(exp.Current()); } @@ -449,11 +445,10 @@ const map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn() case TopAbs_EDGE: { //MESSAGE("edge"); - for (TopExp_Explorer exp(_subShape, TopAbs_VERTEX); exp.More(); - exp.Next()) + for (TopExp_Explorer exp(_subShape, TopAbs_VERTEX); exp.More(); exp.Next()) { - InsertDependence(exp.Current()); - } + InsertDependence(exp.Current()); + } break; } case TopAbs_VERTEX: @@ -1005,9 +1000,12 @@ SMESH_Hypothesis::Hypothesis_Status if ( ret == SMESH_Hypothesis::HYP_OK && !algo->NeedDescretBoundary() && !algo->SupportSubmeshes()) { + TopoDS_Shape algoAssignedTo, otherAssignedTo; + gen->GetAlgo( *_father, _subShape, &algoAssignedTo ); map::reverse_iterator i_sm = _mapDepend.rbegin(); for ( ; ( ret == SMESH_Hypothesis::HYP_OK && i_sm != _mapDepend.rend()) ; ++i_sm ) - if ( gen->GetAlgo( *_father, i_sm->second->_subShape )) + if ( gen->GetAlgo( *_father, i_sm->second->_subShape, &otherAssignedTo ) && + SMESH_MesherHelper::IsSubShape( /*sub=*/otherAssignedTo, /*main=*/algoAssignedTo )) ret = SMESH_Hypothesis::HYP_HIDING_ALGO; } } @@ -1430,18 +1428,29 @@ bool SMESH_subMesh::ComputeStateEngine(int event) else ret = false; } - if (ret && !_alwaysComputed && shape == _subShape) { // check if anything was built - ret = ( GetSubMeshDS() && ( GetSubMeshDS()->NbElements() || GetSubMeshDS()->NbNodes() )); + TopExp_Explorer subS(shape, _subShape.ShapeType()); + if (ret) // check if anything was built + { + for (; ret && subS.More(); subS.Next()) + ret = _father->GetSubMesh( subS.Current() )->IsMeshComputed(); } bool isComputeErrorSet = !CheckComputeError( algo, shape ); if (!ret && !isComputeErrorSet) { // Set _computeError - if ( !_computeError ) - _computeError = SMESH_ComputeError::New(); - if ( _computeError->IsOK() ) - _computeError->myName = COMPERR_ALGO_FAILED; - _computeState = FAILED_TO_COMPUTE; + for (subS.ReInit(); subS.More(); subS.Next()) + { + SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() ); + if ( !sm->IsMeshComputed() ) + { + if ( !sm->_computeError ) + sm->_computeError = SMESH_ComputeError::New(); + if ( sm->_computeError->IsOK() ) + sm->_computeError->myName = COMPERR_ALGO_FAILED; + sm->_computeState = FAILED_TO_COMPUTE; + sm->_computeError->myAlgo = algo; + } + } } if (ret) { @@ -1538,6 +1547,8 @@ bool SMESH_subMesh::ComputeStateEngine(int event) switch (event) { case MODIF_ALGO_STATE: + if ( !IsEmpty() ) + ComputeStateEngine( CLEAN ); algo = gen->GetAlgo((*_father), _subShape); if (algo && !algo->NeedDescretBoundary()) CleanDependsOn(); // clean sub-meshes with event CLEAN diff --git a/src/SMESHDS/SMESHDS_Group.cxx b/src/SMESHDS/SMESHDS_Group.cxx index 46fc68259..e86089c8f 100644 --- a/src/SMESHDS/SMESHDS_Group.cxx +++ b/src/SMESHDS/SMESHDS_Group.cxx @@ -156,7 +156,7 @@ class MyGroupIterator: public SMDS_ElemIterator //purpose : //======================================================================= -SMDS_ElemIteratorPtr SMESHDS_Group::GetElements() +SMDS_ElemIteratorPtr SMESHDS_Group::GetElements() const { return SMDS_ElemIteratorPtr( new MyGroupIterator ( myGroup )); } diff --git a/src/SMESHDS/SMESHDS_Group.hxx b/src/SMESHDS/SMESHDS_Group.hxx index fc4bbc503..5538e1635 100644 --- a/src/SMESHDS/SMESHDS_Group.hxx +++ b/src/SMESHDS/SMESHDS_Group.hxx @@ -54,7 +54,7 @@ class SMESHDS_EXPORT SMESHDS_Group : public SMESHDS_GroupBase virtual bool Contains (const SMDS_MeshElement* elem); - virtual SMDS_ElemIteratorPtr GetElements(); + virtual SMDS_ElemIteratorPtr GetElements() const; bool Add (const int theID); diff --git a/src/SMESHDS/SMESHDS_GroupBase.hxx b/src/SMESHDS/SMESHDS_GroupBase.hxx index 9fefca27d..2782e8951 100644 --- a/src/SMESHDS/SMESHDS_GroupBase.hxx +++ b/src/SMESHDS/SMESHDS_GroupBase.hxx @@ -66,7 +66,7 @@ class SMESHDS_EXPORT SMESHDS_GroupBase virtual bool Contains (const SMDS_MeshElement* elem); - virtual SMDS_ElemIteratorPtr GetElements() = 0; + virtual SMDS_ElemIteratorPtr GetElements() const = 0; int GetID (const int theIndex); // use it for iterations 1..Extent() diff --git a/src/SMESHDS/SMESHDS_GroupOnGeom.cxx b/src/SMESHDS/SMESHDS_GroupOnGeom.cxx index abd5d552b..aad0ee4f2 100644 --- a/src/SMESHDS/SMESHDS_GroupOnGeom.cxx +++ b/src/SMESHDS/SMESHDS_GroupOnGeom.cxx @@ -102,7 +102,7 @@ class MyIterator: public SMDS_ElemIterator //purpose : //======================================================================= -SMDS_ElemIteratorPtr SMESHDS_GroupOnGeom::GetElements() +SMDS_ElemIteratorPtr SMESHDS_GroupOnGeom::GetElements() const { return SMDS_ElemIteratorPtr( new MyIterator ( GetType(), mySubMesh )); } diff --git a/src/SMESHDS/SMESHDS_GroupOnGeom.hxx b/src/SMESHDS/SMESHDS_GroupOnGeom.hxx index bb6f0900d..1b4b5a924 100644 --- a/src/SMESHDS/SMESHDS_GroupOnGeom.hxx +++ b/src/SMESHDS/SMESHDS_GroupOnGeom.hxx @@ -51,7 +51,7 @@ class SMESHDS_EXPORT SMESHDS_GroupOnGeom: public SMESHDS_GroupBase virtual bool Contains (const SMDS_MeshElement* elem); - virtual SMDS_ElemIteratorPtr GetElements(); + virtual SMDS_ElemIteratorPtr GetElements() const; private: diff --git a/src/SMESHDS/SMESHDS_Mesh.cxx b/src/SMESHDS/SMESHDS_Mesh.cxx index 091e4f70c..0ae03d0c5 100644 --- a/src/SMESHDS/SMESHDS_Mesh.cxx +++ b/src/SMESHDS/SMESHDS_Mesh.cxx @@ -61,6 +61,7 @@ SMESHDS_Mesh::SMESHDS_Mesh(int theMeshID, bool theIsEmbeddedMode): { myScript = new SMESHDS_Script(theIsEmbeddedMode); myCurSubMesh = 0; + SetPersistentId(theMeshID); } //======================================================================= @@ -69,6 +70,28 @@ bool SMESHDS_Mesh::IsEmbeddedMode() return myIsEmbeddedMode; } +//================================================================================ +/*! + * \brief Store ID persistent during lifecycle + */ +//================================================================================ + +void SMESHDS_Mesh::SetPersistentId(int id) +{ + if (NbNodes() == 0) + myPersistentID = id; +} +//================================================================================ +/*! + * \brief Return ID persistent during lifecycle + */ +//================================================================================ + +int SMESHDS_Mesh::GetPersistentId() const +{ + return myPersistentID; +} + //======================================================================= //function : ShapeToMesh //purpose : @@ -561,8 +584,8 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, //function : AddPolygonalFace //purpose : //======================================================================= -SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID (std::vector nodes_ids, - const int ID) +SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID (const std::vector& nodes_ids, + const int ID) { SMDS_MeshFace *anElem = SMDS_Mesh::AddPolygonalFaceWithID(nodes_ids, ID); if (anElem) { @@ -572,8 +595,8 @@ SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID (std::vector nodes_ids, } SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID - (std::vector nodes, - const int ID) + (const std::vector& nodes, + const int ID) { SMDS_MeshFace *anElem = SMDS_Mesh::AddPolygonalFaceWithID(nodes, ID); if (anElem) { @@ -588,7 +611,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID } SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFace - (std::vector nodes) + (const std::vector& nodes) { SMDS_MeshFace *anElem = SMDS_Mesh::AddPolygonalFace(nodes); if (anElem) { @@ -606,9 +629,9 @@ SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFace //function : AddPolyhedralVolume //purpose : //======================================================================= -SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolumeWithID (std::vector nodes_ids, - std::vector quantities, - const int ID) +SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolumeWithID (const std::vector& nodes_ids, + const std::vector& quantities, + const int ID) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddPolyhedralVolumeWithID(nodes_ids, quantities, ID); if (anElem) { @@ -618,9 +641,9 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolumeWithID (std::vector nodes } SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolumeWithID - (std::vector nodes, - std::vector quantities, - const int ID) + (const std::vector& nodes, + const std::vector& quantities, + const int ID) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddPolyhedralVolumeWithID(nodes, quantities, ID); if (anElem) { @@ -635,8 +658,8 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolumeWithID } SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolume - (std::vector nodes, - std::vector quantities) + (const std::vector& nodes, + const std::vector& quantities) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddPolyhedralVolume(nodes, quantities); if (anElem) { @@ -1073,15 +1096,13 @@ TopoDS_Shape SMESHDS_Mesh::ShapeToMesh() const bool SMESHDS_Mesh::IsGroupOfSubShapes (const TopoDS_Shape& theShape) const { - if ( myShape.IsSame( theShape )) + if ( myIndexToShape.Contains(theShape) ) return true; - for ( TopoDS_Iterator it( theShape ); it.More(); it.Next() ) { - if (myIndexToShape.Contains( it.Value() ) || - IsGroupOfSubShapes( it.Value() )) + for ( TopoDS_Iterator it( theShape ); it.More(); it.Next() ) + if (IsGroupOfSubShapes( it.Value() )) return true; - } - + return false; } @@ -1205,7 +1226,7 @@ int SMESHDS_Mesh::AddCompoundSubmesh(const TopoDS_Shape& S, TopAbs_ShapeEnum type) { int aMainIndex = 0; - if ( IsGroupOfSubShapes( S ) || (S.ShapeType() == TopAbs_VERTEX && myIndexToShape.Contains(S)) ) + if ( IsGroupOfSubShapes( S )) { aMainIndex = myIndexToShape.Add( S ); bool all = ( type == TopAbs_SHAPE ); @@ -1249,6 +1270,17 @@ const TopoDS_Shape& SMESHDS_Mesh::IndexToShape(int ShapeIndex) const return nullShape; } +//================================================================================ +/*! + * \brief Return max index of sub-mesh + */ +//================================================================================ + +int SMESHDS_Mesh::MaxSubMeshIndex() const +{ + return myShapeIndexToSubMesh.empty() ? 0 : myShapeIndexToSubMesh.rbegin()->first; +} + //======================================================================= //function : ShapeToIndex //purpose : diff --git a/src/SMESHDS/SMESHDS_Mesh.hxx b/src/SMESHDS/SMESHDS_Mesh.hxx index 386abc3d3..7e852c774 100644 --- a/src/SMESHDS/SMESHDS_Mesh.hxx +++ b/src/SMESHDS/SMESHDS_Mesh.hxx @@ -50,7 +50,7 @@ #include #include /* - * Using of native haah_map isn't portable and don't work on WIN32 platform. + * Using of native hash_map isn't portable and don't work on WIN32 platform. * So this functionality implement on new NCollection_DataMap technology */ #include "SMESHDS_DataMapOfShape.hxx" @@ -61,6 +61,8 @@ class SMESHDS_EXPORT SMESHDS_Mesh:public SMDS_Mesh{ public: SMESHDS_Mesh(int theMeshID, bool theIsEmbeddedMode); bool IsEmbeddedMode(); + void SetPersistentId(int id); + int GetPersistentId() const; void ShapeToMesh(const TopoDS_Shape & S); TopoDS_Shape ShapeToMesh() const; @@ -354,27 +356,27 @@ public: const SMDS_MeshNode * n37, const SMDS_MeshNode * n48); - virtual SMDS_MeshFace* AddPolygonalFaceWithID (std::vector nodes_ids, - const int ID); + virtual SMDS_MeshFace* AddPolygonalFaceWithID (const std::vector& nodes_ids, + const int ID); - virtual SMDS_MeshFace* AddPolygonalFaceWithID (std::vector nodes, - const int ID); + virtual SMDS_MeshFace* AddPolygonalFaceWithID (const std::vector& nodes, + const int ID); - virtual SMDS_MeshFace* AddPolygonalFace (std::vector nodes); + virtual SMDS_MeshFace* AddPolygonalFace (const std::vector& nodes); virtual SMDS_MeshVolume* AddPolyhedralVolumeWithID - (std::vector nodes_ids, - std::vector quantities, - const int ID); + (const std::vector& nodes_ids, + const std::vector& quantities, + const int ID); virtual SMDS_MeshVolume* AddPolyhedralVolumeWithID - (std::vector nodes, - std::vector quantities, - const int ID); + (const std::vector& nodes, + const std::vector& quantities, + const int ID); virtual SMDS_MeshVolume* AddPolyhedralVolume - (std::vector nodes, - std::vector quantities); + (const std::vector& nodes, + const std::vector& quantities); void MoveNode(const SMDS_MeshNode *, double x, double y, double z); virtual void RemoveNode(const SMDS_MeshNode *); @@ -423,6 +425,7 @@ public: int ShapeToIndex(const TopoDS_Shape & aShape) const; const TopoDS_Shape& IndexToShape(int ShapeIndex) const; int MaxShapeIndex() const { return myIndexToShape.Extent(); } + int MaxSubMeshIndex() const; SMESHDS_SubMesh * NewSubMesh(int Index); int AddCompoundSubmesh(const TopoDS_Shape& S, TopAbs_ShapeEnum type = TopAbs_SHAPE); @@ -449,7 +452,7 @@ private: if ( it == myShapeIndexToSubMesh.end() ) it = myShapeIndexToSubMesh.insert( std::make_pair(Index, new SMESHDS_SubMesh() )).first; it->second->AddNode( aNode ); // add aNode to submesh - } + } /*int HashCode( const TopoDS_Shape& S, const Standard_Integer theUpper ) const { @@ -462,7 +465,7 @@ private: ShapeToHypothesis myShapeToHypothesis; - int myMeshID; + int myMeshID, myPersistentID; TopoDS_Shape myShape; typedef std::map TShapeIndexToSubMesh; diff --git a/src/SMESHFiltersSelection/SMESH_Type.h b/src/SMESHFiltersSelection/SMESH_Type.h index 4531a8760..89857d89c 100644 --- a/src/SMESHFiltersSelection/SMESH_Type.h +++ b/src/SMESHFiltersSelection/SMESH_Type.h @@ -52,6 +52,11 @@ enum MeshObjectType { SUBMESH_SOLID, SUBMESH_COMPOUND, GROUP, + GROUP_NODE, + GROUP_EDGE, + GROUP_FACE, + GROUP_VOLUME, + GROUP_0D, COMPONENT }; diff --git a/src/SMESHFiltersSelection/SMESH_TypeFilter.cxx b/src/SMESHFiltersSelection/SMESH_TypeFilter.cxx index bfede0418..1fbb37516 100644 --- a/src/SMESHFiltersSelection/SMESH_TypeFilter.cxx +++ b/src/SMESHFiltersSelection/SMESH_TypeFilter.cxx @@ -81,6 +81,7 @@ bool SMESH_TypeFilter::isOk (const SUIT_DataOwner* theDataOwner) const // 4 | |- Applied algorithms ( selectable in Use Case Browser ) // 5 | |- Regular 1D // |- Group Of Nodes + // |- Group 1 if (aLevel <= 0) return false; @@ -172,6 +173,36 @@ bool SMESH_TypeFilter::isOk (const SUIT_DataOwner* theDataOwner) const Ok = true; break; } + case GROUP_NODE: + { + if (aLevel == 3 && (objFather->Tag() == SMESH::Tag_NodeGroups)) + Ok = true; + break; + } + case GROUP_EDGE: + { + if (aLevel == 3 && (objFather->Tag() == SMESH::Tag_EdgeGroups)) + Ok = true; + break; + } + case GROUP_FACE: + { + if (aLevel == 3 && (objFather->Tag() == SMESH::Tag_FaceGroups)) + Ok = true; + break; + } + case GROUP_VOLUME: + { + if (aLevel == 3 && (objFather->Tag() == SMESH::Tag_VolumeGroups)) + Ok = true; + break; + } + case GROUP_0D: + { + if (aLevel == 3 && (objFather->Tag() == SMESH::Tag_VolumeGroups+1)) + Ok = true; + break; + } } } return Ok; diff --git a/src/SMESHGUI/Makefile.am b/src/SMESHGUI/Makefile.am index 1030ffd65..7e7448f59 100644 --- a/src/SMESHGUI/Makefile.am +++ b/src/SMESHGUI/Makefile.am @@ -47,12 +47,10 @@ salomeinclude_HEADERS = \ SMESHGUI_GroupDlg.h \ SMESHGUI_RemoveNodesDlg.h \ SMESHGUI_RemoveElementsDlg.h \ - SMESHGUI_MeshInfosDlg.h \ - SMESHGUI_StandardMeshInfosDlg.h \ - SMESHGUI_WhatIsDlg.h \ + SMESHGUI_MeshInfo.h \ + SMESHGUI_Measurements.h \ SMESHGUI_Preferences_ColorDlg.h \ SMESHGUI_Preferences_ScalarBarDlg.h \ - SMESHGUI_MoveNodesDlg.h \ SMESHGUI_AddMeshElementDlg.h \ SMESHGUI_XmlHandler.h \ SMESHGUI_Filter.h \ @@ -72,7 +70,8 @@ salomeinclude_HEADERS = \ SMESHGUI_ScaleDlg.h \ SMESHGUI_SymmetryDlg.h \ SMESHGUI_SewingDlg.h \ - SMESHGUI_EditMeshDlg.h \ + SMESHGUI_DuplicateNodesDlg.h \ + SMESHGUI_MergeDlg.h \ SMESHGUI_MeshUtils.h \ SMESHGUI_CreatePolyhedralVolumeDlg.h \ SMESHGUI_Operation.h \ @@ -111,12 +110,10 @@ dist_libSMESH_la_SOURCES = \ SMESHGUI_GroupDlg.cxx \ SMESHGUI_RemoveNodesDlg.cxx \ SMESHGUI_RemoveElementsDlg.cxx \ - SMESHGUI_MeshInfosDlg.cxx \ - SMESHGUI_StandardMeshInfosDlg.cxx \ - SMESHGUI_WhatIsDlg.cxx \ + SMESHGUI_MeshInfo.cxx \ + SMESHGUI_Measurements.cxx \ SMESHGUI_Preferences_ColorDlg.cxx \ SMESHGUI_Preferences_ScalarBarDlg.cxx \ - SMESHGUI_MoveNodesDlg.cxx \ SMESHGUI_AddMeshElementDlg.cxx \ SMESHGUI_XmlHandler.cxx \ SMESHGUI_Filter.cxx \ @@ -136,7 +133,8 @@ dist_libSMESH_la_SOURCES = \ SMESHGUI_ScaleDlg.cxx \ SMESHGUI_SymmetryDlg.cxx \ SMESHGUI_SewingDlg.cxx \ - SMESHGUI_EditMeshDlg.cxx \ + SMESHGUI_DuplicateNodesDlg.cxx \ + SMESHGUI_MergeDlg.cxx \ SMESHGUI_Utils.cxx \ SMESHGUI_GEOMGenUtils.cxx \ SMESHGUI_MeshUtils.cxx \ @@ -183,12 +181,10 @@ MOC_FILES = \ SMESHGUI_GroupDlg_moc.cxx \ SMESHGUI_RemoveNodesDlg_moc.cxx \ SMESHGUI_RemoveElementsDlg_moc.cxx \ - SMESHGUI_MeshInfosDlg_moc.cxx \ - SMESHGUI_StandardMeshInfosDlg_moc.cxx \ - SMESHGUI_WhatIsDlg_moc.cxx \ + SMESHGUI_MeshInfo_moc.cxx \ + SMESHGUI_Measurements_moc.cxx \ SMESHGUI_Preferences_ColorDlg_moc.cxx \ SMESHGUI_Preferences_ScalarBarDlg_moc.cxx \ - SMESHGUI_MoveNodesDlg_moc.cxx \ SMESHGUI_AddMeshElementDlg_moc.cxx \ SMESHGUI_FilterDlg_moc.cxx \ SMESHGUI_FilterLibraryDlg_moc.cxx \ @@ -206,7 +202,8 @@ MOC_FILES = \ SMESHGUI_ScaleDlg_moc.cxx \ SMESHGUI_SymmetryDlg_moc.cxx \ SMESHGUI_SewingDlg_moc.cxx \ - SMESHGUI_EditMeshDlg_moc.cxx \ + SMESHGUI_DuplicateNodesDlg_moc.cxx \ + SMESHGUI_MergeDlg_moc.cxx \ SMESHGUI_CreatePolyhedralVolumeDlg_moc.cxx \ SMESHGUI_Operation_moc.cxx \ SMESHGUI_SelectionOp_moc.cxx \ @@ -269,4 +266,5 @@ libSMESH_la_LDFLAGS = \ # resources files nodist_salomeres_DATA= \ SMESH_images.qm \ - SMESH_msg_en.qm + SMESH_msg_en.qm \ + SMESH_msg_fr.qm diff --git a/src/SMESHGUI/SMESHGUI.cxx b/src/SMESHGUI/SMESHGUI.cxx index f777acbc4..6ea18bbf0 100644 --- a/src/SMESHGUI/SMESHGUI.cxx +++ b/src/SMESHGUI/SMESHGUI.cxx @@ -19,12 +19,13 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI.cxx +// Author : Nicolas REJNERI, Open CASCADE S.A.S. -// SMESH SMESHGUI : GUI for SMESH component -// File : SMESHGUI.cxx -// Author : Nicolas REJNERI, Open CASCADE S.A.S. -// SMESH includes -// +#include // E.A. must be included before Python.h to fix compilation on windows +#include "Python.h" +// SMESH includes #include "SMESHGUI.h" #include "SMESHGUI_AddMeshElementDlg.h" #include "SMESHGUI_AddQuadraticElementDlg.h" @@ -35,7 +36,7 @@ #include "SMESHGUI_CreatePolyhedralVolumeDlg.h" #include "SMESHGUI_DeleteGroupDlg.h" #include "SMESHGUI_Displayer.h" -#include "SMESHGUI_EditMeshDlg.h" +#include "SMESHGUI_MergeDlg.h" #include "SMESHGUI_ExtrusionAlongPathDlg.h" #include "SMESHGUI_ExtrusionDlg.h" #include "SMESHGUI_FileInfoDlg.h" @@ -49,11 +50,12 @@ #include "SMESHGUI_Hypotheses.h" #include "SMESHGUI_Make2DFrom3DOp.h" #include "SMESHGUI_MakeNodeAtPointDlg.h" -#include "SMESHGUI_MeshInfosDlg.h" +//#include "SMESHGUI_MeshInfosDlg.h" +#include "SMESHGUI_Measurements.h" +#include "SMESHGUI_MeshInfo.h" #include "SMESHGUI_MeshOp.h" #include "SMESHGUI_MeshOrderOp.h" #include "SMESHGUI_MeshPatternDlg.h" -#include "SMESHGUI_MoveNodesDlg.h" #include "SMESHGUI_MultiEditDlg.h" #include "SMESHGUI_NodesDlg.h" #include "SMESHGUI_Preferences_ColorDlg.h" @@ -67,12 +69,13 @@ #include "SMESHGUI_SewingDlg.h" #include "SMESHGUI_SingleEditDlg.h" #include "SMESHGUI_SmoothingDlg.h" -#include "SMESHGUI_StandardMeshInfosDlg.h" +//#include "SMESHGUI_StandardMeshInfosDlg.h" #include "SMESHGUI_SymmetryDlg.h" #include "SMESHGUI_TranslationDlg.h" #include "SMESHGUI_ScaleDlg.h" #include "SMESHGUI_TransparencyDlg.h" -#include "SMESHGUI_WhatIsDlg.h" +//#include "SMESHGUI_WhatIsDlg.h" +#include "SMESHGUI_DuplicateNodesDlg.h" #include "SMESHGUI_Utils.h" #include "SMESHGUI_MeshUtils.h" @@ -84,7 +87,9 @@ #include #include +#include #include +#include "SMESH_ControlsDef.hxx" // SALOME GUI includes #include @@ -121,19 +126,21 @@ #include #include CORBA_CLIENT_HEADER(SALOMEDS_Attributes) #include CORBA_CLIENT_HEADER(SMESH_MeshEditor) +#include CORBA_CLIENT_HEADER(SMESH_Measurements) // Qt includes // #define INCLUDE_MENUITEM_DEF // VSR commented ???????? #include +#include // BOOST includes #include // VTK includes -#include #include #include #include +#include // SALOME KERNEL includes #include @@ -146,6 +153,10 @@ #include #include +//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 + //namespace{ // Declarations //============================================================= @@ -170,14 +181,14 @@ std::string myExtension; if ( theCommandID == 113 ) { - filter.append( QObject::tr( "MED files (*.med)" ) ); - filter.append( QObject::tr( "All files (*)" ) ); + filter.append( QObject::tr( "MED_FILES_FILTER" ) + " (*.med)" ); + filter.append( QObject::tr( "ALL_FILES_FILTER" ) + " (*)" ); } else if ( theCommandID == 112 ) { - filter.append( QObject::tr( "IDEAS files (*.unv)" ) ); + filter.append( QObject::tr( "IDEAS_FILES_FILTER" ) + " (*.unv)" ); } else if ( theCommandID == 111 ) { - filter.append( QObject::tr( "DAT files (*.dat)" ) ); + filter.append( QObject::tr( "DAT_FILES_FILTER" ) + " (*.dat)" ); } QString anInitialPath = ""; @@ -242,6 +253,13 @@ aPixmap->SetPixMap( "ICON_SMESH_TREE_MESH_IMPORTED" ); if ( theCommandID == 112 ) // mesh names aren't taken from the file for UNV import SMESH::SetName( aMeshSO, QFileInfo(filename).fileName() ); + +#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]->Destroy(); +#endif } else { isEmpty = true; @@ -277,7 +295,7 @@ // actually, the following condition can't be met (added for insurance) if( selected.Extent() == 0 || - selected.Extent() > 1 && theCommandID != 122 && theCommandID != 125 ) + ( selected.Extent() > 1 && theCommandID != 122 && theCommandID != 125 ) ) return; bool hasDuplicatedMeshNames = false; @@ -323,7 +341,7 @@ QList aReservedColors; - QString aFilter, aTitle = QObject::tr("Export mesh"); + QString aFilter, aTitle = QObject::tr("SMESH_EXPORT_MESH"); QMap aFilterMap; QMap aFilterMapSTL; switch ( theCommandID ) { @@ -346,13 +364,13 @@ // PAL18696 QString v21 (aMesh->GetVersionString(SMESH::MED_V2_1, 2)); QString v22 (aMesh->GetVersionString(SMESH::MED_V2_2, 2)); - aFilterMap.insert( QString("MED ") + v21 + " (*.med)", SMESH::MED_V2_1 ); - aFilterMap.insert( QString("MED ") + v22 + " (*.med)", SMESH::MED_V2_2 ); + aFilterMap.insert( QObject::tr( "MED_VX_FILES_FILTER" ).arg( v21 ) + " (*.med)", SMESH::MED_V2_1 ); + aFilterMap.insert( QObject::tr( "MED_VX_FILES_FILTER" ).arg( v22 ) + " (*.med)", SMESH::MED_V2_2 ); } break; case 124: case 121: - aFilter = QObject::tr("DAT files (*.dat)"); + aFilter = QObject::tr( "DAT_FILES_FILTER" ) + " (*.dat)"; break; case 126: case 123: @@ -367,7 +385,7 @@ if (aRet != 0) return; } - aFilter = QObject::tr("IDEAS files (*.unv)"); + aFilter = QObject::tr( "IDEAS_FILES_FILTER" ) + " (*.unv)"; } break; case 140: @@ -395,8 +413,8 @@ return; } - aFilterMapSTL.insert( QObject::tr("STL ASCII (*.stl)"), 1 ); // 1 - ASCII mode - aFilterMapSTL.insert( QObject::tr("STL Binary (*.stl)"), 0 ); // 0 - Binary mode + aFilterMapSTL.insert( QObject::tr( "STL_ASCII_FILES_FILTER" ) + " (*.stl)", 1 ); // 1 - ASCII mode + aFilterMapSTL.insert( QObject::tr( "STL_BIN_FILES_FILTER" ) + " (*.stl)", 0 ); // 0 - Binary mode } break; default: @@ -431,7 +449,7 @@ SUIT_FileDlg* fd = new SUIT_FileDlg( SMESHGUI::desktop(), false, true, true ); fd->setWindowTitle( aTitle ); fd->setNameFilters( filters ); - fd->selectNameFilter( QObject::tr("STL ASCII (*.stl)") ); + fd->selectNameFilter( QObject::tr( "STL_ASCII_FILES_FILTER" ) + " (*.stl)" ); if ( !anInitialPath.isEmpty() ) fd->setDirectory( anInitialPath ); fd->selectFile(aMeshName); @@ -702,6 +720,121 @@ SMESH::RepaintCurrentView(); } + QString functorToString( SMESH::Controls::FunctorPtr f ) + { + QString type = QObject::tr( "UNKNOWN_CONTROL" ); + if ( dynamic_cast< SMESH::Controls::Volume* >( f.get() ) ) + type = QObject::tr( "VOLUME_3D_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::MaxElementLength2D* >( f.get() ) ) + type = QObject::tr( "MAX_ELEMENT_LENGTH_2D" ); + else if ( dynamic_cast< SMESH::Controls::MaxElementLength3D* >( f.get() ) ) + type = QObject::tr( "MAX_ELEMENT_LENGTH_3D" ); + else if ( dynamic_cast< SMESH::Controls::MinimumAngle* >( f.get() ) ) + type = QObject::tr( "MINIMUMANGLE_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::AspectRatio* >( f.get() ) ) + type = QObject::tr( "ASPECTRATIO_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::AspectRatio3D* >( f.get() ) ) + type = QObject::tr( "ASPECTRATIO_3D_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::Warping* >( f.get() ) ) + type = QObject::tr( "WARP_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::Taper* >( f.get() ) ) + type = QObject::tr( "TAPER_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::Skew* >( f.get() ) ) + type = QObject::tr( "SKEW_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::Area* >( f.get() ) ) + type = QObject::tr( "AREA_ELEMENTS" ); + else if ( dynamic_cast< SMESH::Controls::Length* >( f.get() ) ) + type = QObject::tr( "LENGTH_EDGES" ); + else if ( dynamic_cast< SMESH::Controls::Length2D* >( f.get() ) ) + type = QObject::tr( "LENGTH2D_EDGES" ); + else if ( dynamic_cast< SMESH::Controls::MultiConnection* >( f.get() ) ) + type = QObject::tr( "MULTI_BORDERS" ); + else if ( dynamic_cast< SMESH::Controls::MultiConnection2D* >( f.get() ) ) + type = QObject::tr( "MULTI2D_BORDERS" ); + else if ( dynamic_cast< SMESH::Controls::FreeNodes* >( f.get() ) ) + type = QObject::tr( "FREE_NODES" ); + else if ( dynamic_cast< SMESH::Controls::FreeEdges* >( f.get() ) ) + type = QObject::tr( "FREE_EDGES" ); + else if ( dynamic_cast< SMESH::Controls::FreeBorders* >( f.get() ) ) + type = QObject::tr( "FREE_BORDERS" ); + else if ( dynamic_cast< SMESH::Controls::FreeFaces* >( f.get() ) ) + type = QObject::tr( "FREE_FACES" ); + return type; + } + + void SaveDistribution() + { + LightApp_SelectionMgr* aSel = SMESHGUI::selectionMgr(); + SALOME_ListIO selected; + if ( aSel ) + aSel->selectedObjects( selected ); + + if ( selected.Extent() == 1 ) { + Handle(SALOME_InteractiveObject) anIO = selected.First(); + if ( anIO->hasEntry() ) { + SMESH_Actor* anActor = SMESH::FindActorByEntry( anIO->getEntry() ); + if ( anActor && anActor->GetScalarBarActor() && anActor->GetControlMode() != SMESH_Actor::eNone ) { + SMESH_ScalarBarActor* aScalarBarActor = anActor->GetScalarBarActor(); + SMESH::Controls::FunctorPtr aFunctor = anActor->GetFunctor(); + if ( aScalarBarActor && aFunctor ) { + SMESH::Controls::NumericalFunctor* aNumFun = dynamic_cast( aFunctor.get() ); + if ( aNumFun ) { + int nbRanges = aScalarBarActor->GetMaximumNumberOfColors(); + std::vector nbEvents; + std::vector funValues; + aNumFun->GetHistogram( nbRanges, nbEvents, funValues ); + QString anInitialPath = ""; + if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() ) + anInitialPath = QDir::currentPath(); + QString aMeshName = anIO->getName(); + QStringList filter; + filter.append( QObject::tr( "TEXT_FILES_FILTER" ) + " (*.txt)" ); + filter.append( QObject::tr( "ALL_FILES_FILTER" ) + " (*)" ); + QString aFilename = anInitialPath + "/" + aMeshName + "_" + + functorToString( aFunctor ).toLower().simplified().replace( QRegExp( " |-" ), "_" ) + ".txt"; + aFilename = SUIT_FileDlg::getFileName( SMESHGUI::desktop(), + aFilename, + filter, + QObject::tr( "SMESH_SAVE_DISTRIBUTION" ), + false ); + if ( !aFilename.isEmpty() ) { + QFile f( aFilename ); + if ( f.open( QFile::WriteOnly | QFile::Truncate ) ) { + QTextStream out( &f ); + out << "# Mesh: " << aMeshName << endl; + out << "# Control: " << functorToString( aFunctor ) << endl; + out << "#" << endl; + out.setFieldWidth( 10 ); + for ( int i = 0; i < qMin( nbEvents.size(), funValues.size()-1 ); i++ ) + out << funValues[i] << "\t" << funValues[i+1] << "\t" << nbEvents[i] << endl; + f.close(); + } + } + } + } + } + } + } + } + + void ShowDistribution() { + LightApp_SelectionMgr* aSel = SMESHGUI::selectionMgr(); + SALOME_ListIO selected; + if ( aSel ) + aSel->selectedObjects( selected ); + + if ( selected.Extent() == 1 ) { + Handle(SALOME_InteractiveObject) anIO = selected.First(); + if ( anIO->hasEntry() ) { + SMESH_Actor* anActor = SMESH::FindActorByEntry( anIO->getEntry() ); + if ( anActor && anActor->GetScalarBarActor() && anActor->GetControlMode() != SMESH_Actor::eNone ) { + SMESH_ScalarBarActor *aScalarBarActor = anActor->GetScalarBarActor(); + aScalarBarActor->SetDistributionVisibility(!aScalarBarActor->GetDistributionVisibility()); + } + } + } + } + void DisableAutoColor(){ LightApp_SelectionMgr *aSel = SMESHGUI::selectionMgr(); SALOME_ListIO selected; @@ -728,136 +861,144 @@ if( !aSel || !appStudy ) return; + if( theCommandID == 1134 ) { // Clipping dialog can be activated without selection + if( SMESHGUI* aModule = SMESHGUI::GetSMESHGUI() ) { + aModule->EmitSignalDeactivateDialog(); + if( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( aModule ) ) + (new SMESHGUI_ClippingDlg( aModule, aViewWindow ))->show(); + } + return; + } + _PTR(Study) aStudy = appStudy->studyDS(); aSel->selectedObjects( selected ); if(selected.Extent() >= 1){ switch(theCommandID){ - case 1134:{ - SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog(); - (new SMESHGUI_ClippingDlg( SMESHGUI::GetSMESHGUI() ))->show(); - return; - } case 1133:{ SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog(); (new SMESHGUI_TransparencyDlg( SMESHGUI::GetSMESHGUI() ))->show(); return; - }} - SALOME_ListIteratorOfListIO It( selected ); - for( ; It.More(); It.Next()){ - Handle(SALOME_InteractiveObject) IObject = It.Value(); - if(IObject->hasEntry()){ - if(SMESH_Actor *anActor = SMESH::FindActorByEntry(IObject->getEntry())){ - switch(theCommandID){ - case 211: - anActor->SetRepresentation(SMESH_Actor::eEdge); - break; - case 212: - anActor->SetRepresentation(SMESH_Actor::eSurface); - break; - case 213: - if(anActor->IsShrunk()) - anActor->UnShrink(); - else - anActor->SetShrink(); - break; - case 215: - anActor->SetRepresentation(SMESH_Actor::ePoint); - break; - case 231: - if(anActor->GetQuadratic2DRepresentation() != SMESH_Actor::eLines) - anActor->SetQuadratic2DRepresentation(SMESH_Actor::eLines); - break; - case 232: - if(anActor->GetQuadratic2DRepresentation() != SMESH_Actor::eArcs) - anActor->SetQuadratic2DRepresentation(SMESH_Actor::eArcs); - break; - case 1132:{ + } + case 1132:{ + QColor c, e, b, n, c0D, o; + int size0D = 0; + int Edgewidth = 0; + vtkFloatingPointType Shrink = 0.0; + vtkFloatingPointType faces_orientation_scale = 0.0; + bool faces_orientation_3dvectors = false; + + VTK::MarkerType aMarkerTypeCurrent = VTK::MT_NONE; + VTK::MarkerScale aMarkerScaleCurrent = VTK::MS_NONE; + int aMarkerTextureCurrent = 0; + + SALOME_ListIteratorOfListIO It( selected ); + for( ; It.More(); It.Next()){ + Handle(SALOME_InteractiveObject) IObject = It.Value(); + if(IObject->hasEntry()){ + if(SMESH_Actor *anActor = SMESH::FindActorByEntry(IObject->getEntry())){ vtkFloatingPointType color[3]; anActor->GetSufaceColor(color[0], color[1], color[2]); int c0 = int (color[0] * 255); int c1 = int (color[1] * 255); int c2 = int (color[2] * 255); - QColor c(c0, c1, c2); + c.setRgb(c0, c1, c2); vtkFloatingPointType edgecolor[3]; anActor->GetEdgeColor(edgecolor[0], edgecolor[1], edgecolor[2]); c0 = int (edgecolor[0] * 255); c1 = int (edgecolor[1] * 255); c2 = int (edgecolor[2] * 255); - QColor e(c0, c1, c2); + e.setRgb(c0, c1, c2); vtkFloatingPointType backfacecolor[3]; anActor->GetBackSufaceColor(backfacecolor[0], backfacecolor[1], backfacecolor[2]); c0 = int (backfacecolor[0] * 255); c1 = int (backfacecolor[1] * 255); c2 = int (backfacecolor[2] * 255); - QColor b(c0, c1, c2); + b.setRgb(c0, c1, c2); vtkFloatingPointType nodecolor[3]; anActor->GetNodeColor(nodecolor[0], nodecolor[1], nodecolor[2]); c0 = int (nodecolor[0] * 255); c1 = int (nodecolor[1] * 255); c2 = int (nodecolor[2] * 255); - QColor n(c0, c1, c2); + n.setRgb(c0, c1, c2); vtkFloatingPointType color0D[3]; anActor->Get0DColor(color0D[0], color0D[1], color0D[2]); c0 = int (color0D[0] * 255); c1 = int (color0D[1] * 255); c2 = int (color0D[2] * 255); - QColor c0D(c0, c1, c2); + c0D.setRgb(c0, c1, c2); - int size0D = (int)anActor->Get0DSize(); + size0D = (int)anActor->Get0DSize(); if(size0D == 0) size0D = 1; - int Edgewidth = (int)anActor->GetLineWidth(); + Edgewidth = (int)anActor->GetLineWidth(); if(Edgewidth == 0) Edgewidth = 1; - vtkFloatingPointType Shrink = anActor->GetShrinkFactor(); + Shrink = anActor->GetShrinkFactor(); vtkFloatingPointType faces_orientation_color[3]; anActor->GetFacesOrientationColor(faces_orientation_color); c0 = int (faces_orientation_color[0] * 255); c1 = int (faces_orientation_color[1] * 255); c2 = int (faces_orientation_color[2] * 255); - QColor o(c0, c1, c2); - - vtkFloatingPointType faces_orientation_scale = anActor->GetFacesOrientationScale(); - bool faces_orientation_3dvectors = anActor->GetFacesOrientation3DVectors(); - - SMESHGUI_Preferences_ColorDlg *aDlg = - new SMESHGUI_Preferences_ColorDlg( SMESHGUI::GetSMESHGUI() ); - aDlg->SetColor(1, c); - aDlg->SetColor(2, e); - aDlg->SetColor(3, n); - aDlg->SetColor(4, b); - aDlg->SetColor(5, c0D); - aDlg->SetColor(6, o); - aDlg->SetIntValue(1, Edgewidth); - aDlg->SetIntValue(2, int(Shrink*100.)); - aDlg->SetIntValue(3, size0D); - aDlg->SetDoubleValue(1, faces_orientation_scale); - aDlg->SetBooleanValue(1, faces_orientation_3dvectors); - - aDlg->setCustomMarkerMap( theMarkerMap[ aStudy->StudyId() ] ); - - VTK::MarkerType aMarkerTypeCurrent = anActor->GetMarkerType(); - VTK::MarkerScale aMarkerScaleCurrent = anActor->GetMarkerScale(); - int aMarkerTextureCurrent = anActor->GetMarkerTexture(); - if( aMarkerTypeCurrent != VTK::MT_USER ) - aDlg->setStandardMarker( aMarkerTypeCurrent, aMarkerScaleCurrent ); - else - aDlg->setCustomMarker( aMarkerTextureCurrent ); - - if(aDlg->exec()){ - QColor color = aDlg->GetColor(1); - QColor edgecolor = aDlg->GetColor(2); - QColor nodecolor = aDlg->GetColor(3); - QColor backfacecolor = aDlg->GetColor(4); - QColor color0D = aDlg->GetColor(5); - QColor faces_orientation_color = aDlg->GetColor(6); + o.setRgb(c0, c1, c2); + + faces_orientation_scale = anActor->GetFacesOrientationScale(); + faces_orientation_3dvectors = anActor->GetFacesOrientation3DVectors(); + + aMarkerTypeCurrent = anActor->GetMarkerType(); + aMarkerScaleCurrent = anActor->GetMarkerScale(); + aMarkerTextureCurrent = anActor->GetMarkerTexture(); + + // even if there are multiple objects in the selection, + // we need only the first one to get values for the dialog + break; + } + } + } + + SMESHGUI_Preferences_ColorDlg *aDlg = + new SMESHGUI_Preferences_ColorDlg( SMESHGUI::GetSMESHGUI() ); + aDlg->SetColor(1, c); + aDlg->SetColor(2, e); + aDlg->SetColor(3, n); + aDlg->SetColor(4, b); + aDlg->SetColor(5, c0D); + aDlg->SetColor(6, o); + aDlg->SetIntValue(1, Edgewidth); + aDlg->SetIntValue(2, int(Shrink*100.)); + aDlg->SetIntValue(3, size0D); + aDlg->SetDoubleValue(1, faces_orientation_scale); + aDlg->SetBooleanValue(1, faces_orientation_3dvectors); + + aDlg->setCustomMarkerMap( theMarkerMap[ aStudy->StudyId() ] ); + + if( aMarkerTypeCurrent != VTK::MT_USER ) + aDlg->setStandardMarker( aMarkerTypeCurrent, aMarkerScaleCurrent ); + else + aDlg->setCustomMarker( aMarkerTextureCurrent ); + + if(aDlg->exec()){ + QColor color = aDlg->GetColor(1); + QColor edgecolor = aDlg->GetColor(2); + QColor nodecolor = aDlg->GetColor(3); + QColor backfacecolor = aDlg->GetColor(4); + QColor color0D = aDlg->GetColor(5); + QColor faces_orientation_color = aDlg->GetColor(6); + + /* Point marker */ + theMarkerMap[ aStudy->StudyId() ] = aDlg->getCustomMarkerMap(); + + SALOME_ListIteratorOfListIO It( selected ); + for( ; It.More(); It.Next()){ + Handle(SALOME_InteractiveObject) IObject = It.Value(); + if(IObject->hasEntry()){ + if(SMESH_Actor *anActor = SMESH::FindActorByEntry(IObject->getEntry())){ /* actor color and backface color */ anActor->SetSufaceColor(vtkFloatingPointType (color.red()) / 255., vtkFloatingPointType (color.green()) / 255., @@ -894,9 +1035,6 @@ anActor->SetFacesOrientationScale(aDlg->GetDoubleValue(1)); anActor->SetFacesOrientation3DVectors(aDlg->GetBooleanValue(1)); - /* Point marker */ - theMarkerMap[ aStudy->StudyId() ] = aDlg->getCustomMarkerMap(); - VTK::MarkerType aMarkerTypeNew = aDlg->getMarkerType(); VTK::MarkerScale aMarkerScaleNew = aDlg->getStandardMarkerScale(); int aMarkerTextureNew = aDlg->getCustomMarkerID(); @@ -927,11 +1065,45 @@ aGroupColor.B = (float)aColor.blue() / 255.0; aGroupObject->SetColor( aGroupColor ); } - - delete aDlg; } + } + } + SMESH::RepaintCurrentView(); + } + delete aDlg; + return; + } + } + SALOME_ListIteratorOfListIO It( selected ); + for( ; It.More(); It.Next()){ + Handle(SALOME_InteractiveObject) IObject = It.Value(); + if(IObject->hasEntry()){ + if(SMESH_Actor *anActor = SMESH::FindActorByEntry(IObject->getEntry())){ + switch(theCommandID){ + case 211: + anActor->SetRepresentation(SMESH_Actor::eEdge); + break; + case 212: + anActor->SetRepresentation(SMESH_Actor::eSurface); + break; + case 213: + if(anActor->IsShrunk()) + anActor->UnShrink(); + else + anActor->SetShrink(); + break; + case 215: + anActor->SetRepresentation(SMESH_Actor::ePoint); + break; + case 231: + if(anActor->GetQuadratic2DRepresentation() != SMESH_Actor::eLines) + anActor->SetQuadratic2DRepresentation(SMESH_Actor::eLines); + break; + case 232: + if(anActor->GetQuadratic2DRepresentation() != SMESH_Actor::eArcs) + anActor->SetQuadratic2DRepresentation(SMESH_Actor::eArcs); break; - }} + } } } } @@ -949,77 +1121,66 @@ if( !selected.IsEmpty() ){ Handle(SALOME_InteractiveObject) anIO = selected.First(); if(!anIO.IsNull()){ - QString aTitle; SMESH_Actor::eControl aControl = SMESH_Actor::eNone; if(SMESH_Actor *anActor = SMESH::FindActorByEntry(anIO->getEntry())){ switch ( theCommandID ){ case 6001: - aTitle = QObject::tr( "LENGTH_EDGES" ); aControl = SMESH_Actor::eLength; break; case 6018: - aTitle = QObject::tr( "LENGTH2D_EDGES" ); aControl = SMESH_Actor::eLength2D; break; case 6002: - aTitle = QObject::tr( "FREE_EDGES" ); aControl = SMESH_Actor::eFreeEdges; break; case 6003: - aTitle = QObject::tr( "FREE_BORDERS" ); aControl = SMESH_Actor::eFreeBorders; break; case 6004: - aTitle = QObject::tr( "MULTI_BORDERS" ); aControl = SMESH_Actor::eMultiConnection; break; case 6005: - aTitle = QObject::tr( "FREE_NODES" ); aControl = SMESH_Actor::eFreeNodes; break; case 6019: - aTitle = QObject::tr( "MULTI2D_BORDERS" ); aControl = SMESH_Actor::eMultiConnection2D; break; case 6011: - aTitle = QObject::tr( "AREA_ELEMENTS" ); aControl = SMESH_Actor::eArea; break; case 6012: - aTitle = QObject::tr( "TAPER_ELEMENTS" ); aControl = SMESH_Actor::eTaper; break; case 6013: - aTitle = QObject::tr( "ASPECTRATIO_ELEMENTS" ); aControl = SMESH_Actor::eAspectRatio; break; case 6017: - aTitle = QObject::tr( "ASPECTRATIO_3D_ELEMENTS" ); aControl = SMESH_Actor::eAspectRatio3D; break; case 6014: - aTitle = QObject::tr( "MINIMUMANGLE_ELEMENTS" ); aControl = SMESH_Actor::eMinimumAngle; break; case 6015: - aTitle = QObject::tr( "WARP_ELEMENTS" ); aControl = SMESH_Actor::eWarping; break; case 6016: - aTitle = QObject::tr( "SKEW_ELEMENTS" ); aControl = SMESH_Actor::eSkew; break; case 6009: - aTitle = QObject::tr( "SMESH_VOLUME" ); aControl = SMESH_Actor::eVolume3D; break; case 6021: - aTitle = QObject::tr( "FREE_FACES" ); aControl = SMESH_Actor::eFreeFaces; break; + case 6022: + aControl = SMESH_Actor::eMaxElementLength2D; + break; + case 6023: + aControl = SMESH_Actor::eMaxElementLength3D; + break; } anActor->SetControlMode(aControl); - anActor->GetScalarBarActor()->SetTitle(aTitle.toLatin1().data()); + anActor->GetScalarBarActor()->SetTitle( functorToString( anActor->GetFunctor() ).toLatin1().constData() ); SMESH::RepaintCurrentView(); } } @@ -1154,7 +1315,7 @@ SalomeApp_Application* anApp = dynamic_cast( SUIT_Session::session()->activeApplication() ); SUIT_ViewManager* vm = anApp->activeViewManager(); - int nbSf = vm->getViewsCount(); + int nbSf = vm ? vm->getViewsCount() : 0; SALOME_ListIteratorOfListIO It(selected); @@ -1196,7 +1357,7 @@ std::string anEntry = SO->GetID(); /** Erase graphical object **/ - if(SO->FindAttribute(anAttr, "AttributeIOR")){ + if(SO->FindAttribute(anAttr, "AttributeIOR") && vm ){ QVector aViews = vm->getViews(); for(int i = 0; i < nbSf; i++){ SUIT_ViewWindow *sf = aViews[i]; @@ -1286,8 +1447,15 @@ LightApp_Module( "SMESH" ) myState = -1; myDisplayer = 0; + myEventCallbackCommand = vtkCallbackCommand::New(); + myEventCallbackCommand->Delete(); + myEventCallbackCommand->SetClientData( this ); + myEventCallbackCommand->SetCallback( SMESHGUI::ProcessEvents ); + myPriority = 0.0; + SMESH::GetFilterManager(); SMESH::GetPattern(); + SMESH::GetMeasurements(); /* load resources for all available meshers */ SMESH::InitAvailableHypotheses(); @@ -1300,8 +1468,12 @@ LightApp_Module( "SMESH" ) //============================================================================= SMESHGUI::~SMESHGUI() { +#ifdef WITHGENERICOBJ SMESH::GetFilterManager()->Destroy(); + SMESH::GetMeasurements()->Destroy(); +#endif SMESH::GetFilterManager() = SMESH::FilterManager::_nil(); + SMESH::GetMeasurements() = SMESH::Measurements::_nil(); } //============================================================================= @@ -1318,13 +1490,22 @@ LightApp_SelectionMgr* SMESHGUI::selectionMgr() return 0; } -bool SMESHGUI::automaticUpdate() +//============================================================================= +/*! + * + */ +//============================================================================= +bool SMESHGUI::automaticUpdate(unsigned int requestedSize, bool* limitExceeded) { SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr(); if ( !resMgr ) return false; - return resMgr->booleanValue( "SMESH", "auto_update", false ); + bool autoUpdate = resMgr->booleanValue( "SMESH", "auto_update", false ); + long updateLimit = resMgr->integerValue( "SMESH", "update_limit", 500000 ); + bool exceeded = updateLimit > 0 && requestedSize > updateLimit; + if ( limitExceeded ) *limitExceeded = autoUpdate && exceeded; + return autoUpdate && !exceeded; } //============================================================================= @@ -1639,6 +1820,19 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) SMESHGUI_Preferences_ScalarBarDlg::ScalarBarProperties( this ); break; } + case 202: + { + // dump control distribution data to the text file + ::SaveDistribution(); + break; + } + + case 203: + { + // show/ distribution + ::ShowDistribution(); + break; + } // Auto-color case 1136: @@ -1666,7 +1860,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) case 232: ::SetDisplayMode(theCommandID, myMarkerMap); break; - + // Display Entity case 216: // 0D elements case 217: // Edges @@ -1773,7 +1967,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) } else aSel->setSelectedObjects( to_process ); - + break; } @@ -1804,20 +1998,6 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) break; } - case 406: // MOVE NODE - { - if ( !vtkwnd ) - { - SUIT_MessageBox::warning( desktop(), tr( "SMESH_WRN_WARNING" ), - tr( "NOT_A_VTK_VIEWER" ) ); - break; - } - - if(checkLock(aStudy)) break; - ( new SMESHGUI_MoveNodesDlg( this ) )->show(); - break; - } - case 701: // COMPUTE MESH case 711: // PRECOMPUTE MESH case 712: // EVALUATE MESH @@ -2231,7 +2411,9 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) } case 900: // MESH INFOS + case 903: // WHAT IS { + int page = theCommandID == 900 ? SMESHGUI_MeshInfoDlg::BaseInfo : SMESHGUI_MeshInfoDlg::ElemInfo; EmitSignalDeactivateDialog(); LightApp_SelectionMgr *aSel = SMESHGUI::selectionMgr(); SALOME_ListIO selected; @@ -2239,21 +2421,20 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) aSel->selectedObjects( selected ); if ( selected.Extent() > 1 ) { // a dlg for each IO - SALOME_ListIO IOs; - SALOME_ListIteratorOfListIO It (selected); + SALOME_ListIteratorOfListIO It( selected ); for ( ; It.More(); It.Next() ) { - IOs.Clear(); IOs.Append( It.Value() ); - aSel->setSelectedObjects( IOs ); - ( new SMESHGUI_MeshInfosDlg( this ) )->show(); + SMESHGUI_MeshInfoDlg* dlg = new SMESHGUI_MeshInfoDlg( SMESHGUI::desktop(), page ); + dlg->showInfo( It.Value() ); + dlg->show(); } - // restore selection - aSel->setSelectedObjects( selected ); } - else - ( new SMESHGUI_MeshInfosDlg( this ) )->show(); + else { + SMESHGUI_MeshInfoDlg* dlg = new SMESHGUI_MeshInfoDlg( SMESHGUI::desktop(), page ); + dlg->show(); + } break; } - + /* case 902: // STANDARD MESH INFOS { EmitSignalDeactivateDialog(); @@ -2278,13 +2459,13 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) ( new SMESHGUI_StandardMeshInfosDlg( this ) )->show(); break; } - case 903: // WHAT IS { EmitSignalDeactivateDialog(); ( new SMESHGUI_WhatIsDlg( this ) )->show(); break; } + */ case 904: // FIND ELEM { @@ -2569,6 +2750,44 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) updateObjBrowser(); break; } + case 4044: // REMOVE ORPHAN NODES + { + if(checkLock(aStudy)) break; + SALOME_ListIO selected; + if( LightApp_SelectionMgr *aSel = SMESHGUI::selectionMgr() ) + aSel->selectedObjects( selected ); + if ( selected.Extent() == 1 ) { + Handle(SALOME_InteractiveObject) anIO = selected.First(); + SMESH::SMESH_Mesh_var aMesh = SMESH::GetMeshByIO(anIO); + if ( !aMesh->_is_nil() ) { + bool confirm = SUIT_MessageBox::question( SMESHGUI::desktop(), + tr( "SMESH_WARNING" ), + tr( "REMOVE_ORPHAN_NODES_QUESTION"), + SUIT_MessageBox::Yes | + SUIT_MessageBox::No, + SUIT_MessageBox::No ) == SUIT_MessageBox::Yes; + if( confirm ) { + try { + SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor(); + int removed = aMeshEditor->RemoveOrphanNodes(); + SUIT_MessageBox::information(SMESHGUI::desktop(), + tr("SMESH_INFORMATION"), + tr("NB_NODES_REMOVED").arg(removed)); + if ( removed > 0 ) { + SMESH::UpdateView(); + SMESHGUI::Modified(); + } + } + catch (const SALOME::SALOME_Exception& S_ex) { + SalomeApp_Tools::QtCatchCorbaException(S_ex); + } + catch (...) { + } + } + } + } + break; + } case 4051: // RENUMBERING NODES { if(checkLock(aStudy)) break; @@ -2654,7 +2873,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) if(checkLock(aStudy)) break; if(vtkwnd) { EmitSignalDeactivateDialog(); - ( new SMESHGUI_EditMeshDlg( this, 0 ) )->show(); + ( new SMESHGUI_MergeDlg( this, 0 ) )->show(); } else { SUIT_MessageBox::warning(SMESHGUI::desktop(), @@ -2667,7 +2886,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) if (checkLock(aStudy)) break; if (vtkwnd) { EmitSignalDeactivateDialog(); - ( new SMESHGUI_EditMeshDlg( this, 1 ) )->show(); + ( new SMESHGUI_MergeDlg( this, 1 ) )->show(); } else { SUIT_MessageBox::warning(SMESHGUI::desktop(), tr("SMESH_WRN_WARNING"), tr("SMESH_WRN_VIEWER_VTK")); @@ -2693,6 +2912,20 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) break; } + case 4069: // DUPLICATE NODES + { + if(checkLock(aStudy)) break; + if ( vtkwnd ) { + EmitSignalDeactivateDialog(); + ( new SMESHGUI_DuplicateNodesDlg( this ) )->show(); + } + else { + SUIT_MessageBox::warning(SMESHGUI::desktop(), + tr("SMESH_WRN_WARNING"), tr("SMESH_WRN_VIEWER_VTK")); + } + break; + } + case 5105: // Library of selection filters { static QList aTypes; @@ -2727,6 +2960,8 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) case 6005: case 6009: case 6021: + case 6022: + case 6023: if ( vtkwnd ) { LightApp_SelectionMgr* mgr = selectionMgr(); @@ -2777,8 +3012,9 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) LightApp_SelectionMgr* mgr = selectionMgr(); SALOME_ListIO selected; mgr->selectedObjects( selected ); - if (selected.Extent() == 1) { - Handle(SALOME_InteractiveObject) anIObject = selected.First(); + SALOME_ListIteratorOfListIO it(selected); + for( ; it.More(); it.Next()) { + Handle(SALOME_InteractiveObject) anIObject = it.Value(); if(anIObject->hasEntry()) if(SMESH_Actor *anActor = SMESH::FindActorByEntry(anIObject->getEntry())){ anActor->SetCellsLabeled( !anActor->GetCellsLabeled() ); @@ -2786,6 +3022,15 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) } break; } + case 501: + case 502: + { + int page = theCommandID == 501 ? SMESHGUI_MeasureDlg::MinDistance : SMESHGUI_MeasureDlg::BoundingBox; + EmitSignalDeactivateDialog(); + SMESHGUI_MeasureDlg* dlg = new SMESHGUI_MeasureDlg( SMESHGUI::desktop(), page ); + dlg->show(); + break; + } } anApp->updateActions(); //SRN: To update a Save button in the toolbar @@ -2841,7 +3086,8 @@ void SMESHGUI::BuildPresentation( const Handle(SALOME_InteractiveObject) & theIO // function : createSMESHAction // purpose : //======================================================================= -void SMESHGUI::createSMESHAction( const int id, const QString& po_id, const QString& icon_id, const int key, const bool toggle ) +void SMESHGUI::createSMESHAction( const int id, const QString& po_id, const QString& icon_id, + const int key, const bool toggle, const QString& shortcutAction ) { QIcon icon; QWidget* parent = application()->desktop(); @@ -2858,7 +3104,8 @@ void SMESHGUI::createSMESHAction( const int id, const QString& po_id, const QStr menu = tr( QString( "MEN_%1" ).arg( po_id ).toLatin1().data() ), status_bar = tr( QString( "STB_%1" ).arg( po_id ).toLatin1().data() ); - createAction( id, tooltip, icon, menu, status_bar, key, parent, toggle, this, SLOT( OnGUIEvent() ) ); + createAction( id, tooltip, icon, menu, status_bar, key, parent, + toggle, this, SLOT( OnGUIEvent() ), shortcutAction ); } //======================================================================= @@ -2948,12 +3195,14 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 814, "UNDERLYING_ELEMS","ICON_UNDERLYING_ELEMS" ); createSMESHAction( 813, "DEL_GROUP", "ICON_DEL_GROUP" ); createSMESHAction( 900, "ADV_INFO", "ICON_ADV_INFO" ); - createSMESHAction( 902, "STD_INFO", "ICON_STD_INFO" ); + //createSMESHAction( 902, "STD_INFO", "ICON_STD_INFO" ); createSMESHAction( 903, "WHAT_IS", "ICON_WHAT_IS" ); createSMESHAction( 904, "FIND_ELEM", "ICON_FIND_ELEM" ); createSMESHAction( 6001, "LENGTH", "ICON_LENGTH", 0, true ); createSMESHAction( 6002, "FREE_EDGE", "ICON_FREE_EDGE", 0, true ); createSMESHAction( 6021, "FREE_FACES", "ICON_FREE_FACES", 0, true ); + createSMESHAction( 6022, "MAX_ELEMENT_LENGTH_2D", "ICON_MAX_ELEMENT_LENGTH_2D", 0, true ); + createSMESHAction( 6023, "MAX_ELEMENT_LENGTH_3D", "ICON_MAX_ELEMENT_LENGTH_3D", 0, true ); createSMESHAction( 6003, "FREE_BORDER", "ICON_FREE_EDGE_2D", 0, true ); createSMESHAction( 6004, "CONNECTION", "ICON_CONNECTION", 0, true ); createSMESHAction( 6005, "FREE_NODE", "ICON_FREE_NODE", 0, true ); @@ -2977,6 +3226,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 4032, "HEXA", "ICON_DLG_HEXAS" ); createSMESHAction( 4041, "REMOVE_NODES", "ICON_DLG_REM_NODE" ); createSMESHAction( 4042, "REMOVE_ELEMENTS", "ICON_DLG_REM_ELEMENT" ); + createSMESHAction( 4044, "REMOVE_ORPHAN_NODES", "ICON_DLG_REM_ORPHAN_NODES" ); createSMESHAction( 4043, "CLEAR_MESH" , "ICON_CLEAR_MESH" ); createSMESHAction( 4051, "RENUM_NODES", "ICON_DLG_RENUMBERING_NODES" ); createSMESHAction( 4052, "RENUM_ELEMENTS", "ICON_DLG_RENUMBERING_ELEMENTS" ); @@ -2986,9 +3236,9 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 4064, "SEW", "ICON_SMESH_SEWING_FREEBORDERS" ); createSMESHAction( 4065, "MERGE", "ICON_SMESH_MERGE_NODES" ); createSMESHAction( 4066, "MERGE_ELEMENTS", "ICON_DLG_MERGE_ELEMENTS" ); - createSMESHAction( 4067, "MESH_THROU_POINT","ICON_DLG_MESH_THROU_POINT" ); + createSMESHAction( 4067, "MESH_THROU_POINT","ICON_DLG_MOVE_NODE" ); createSMESHAction( 4068, "SCALE", "ICON_DLG_MESH_SCALE" ); - createSMESHAction( 406, "MOVE", "ICON_DLG_MOVE_NODE" ); + createSMESHAction( 4069, "DUPLICATE_NODES", "ICON_SMESH_DUPLICATE_NODES" ); createSMESHAction( 407, "INV", "ICON_DLG_MESH_DIAGONAL" ); createSMESHAction( 408, "UNION2", "ICON_UNION2TRI" ); createSMESHAction( 409, "ORIENT", "ICON_DLG_MESH_ORIENTATION" ); @@ -3004,6 +3254,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 419, "SPLIT_TO_TETRA", "ICON_SPLIT_TO_TETRA" ); createSMESHAction( 200, "RESET" ); createSMESHAction( 201, "SCALAR_BAR_PROP" ); + createSMESHAction( 202, "SAVE_DISTRIBUTION" ); + createSMESHAction( 203, "SHOW_DISTRIBUTION","",0, true ); createSMESHAction( 211, "WIRE", "ICON_WIRE", 0, true ); createSMESHAction( 212, "SHADE", "ICON_SHADE", 0, true ); createSMESHAction( 213, "SHRINK", "ICON_SHRINK", 0, true ); @@ -3033,6 +3285,9 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 1137, "DISABLE_AUTO_COLOR" ); createSMESHAction( 2000, "CTRL" ); + createSMESHAction( 501, "MEASURE_MIN_DIST", "ICON_MEASURE_MIN_DIST" ); + createSMESHAction( 502, "MEASURE_BND_BOX", "ICON_MEASURE_BND_BOX" ); + createSMESHAction( 300, "ERASE" ); createSMESHAction( 301, "DISPLAY" ); createSMESHAction( 302, "DISPLAY_ONLY" ); @@ -3046,18 +3301,23 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 4040, "QUADRATIC_HEXAHEDRON", "ICON_DLG_QUADRATIC_HEXAHEDRON" ); // ----- create menu -------------- - int fileId = createMenu( tr( "MEN_FILE" ), -1, 1 ), - editId = createMenu( tr( "MEN_EDIT" ), -1, 3 ), - toolsId = createMenu( tr( "MEN_TOOLS" ), -1, 5, 50 ), - meshId = createMenu( tr( "MEN_MESH" ), -1, 70, 10 ), - ctrlId = createMenu( tr( "MEN_CTRL" ), -1, 60, 10 ), - modifyId = createMenu( tr( "MEN_MODIFY" ), -1, 40, 10 ), - viewId = createMenu( tr( "MEN_VIEW" ), -1, 2 ); + int fileId = createMenu( tr( "MEN_FILE" ), -1, 1 ), + editId = createMenu( tr( "MEN_EDIT" ), -1, 3 ), + toolsId = createMenu( tr( "MEN_TOOLS" ), -1, 5, 50 ), + meshId = createMenu( tr( "MEN_MESH" ), -1, 70, 10 ), + ctrlId = createMenu( tr( "MEN_CTRL" ), -1, 60, 10 ), + modifyId = createMenu( tr( "MEN_MODIFY" ), -1, 40, 10 ), + measureId = createMenu( tr( "MEN_MEASURE" ), -1, 50, 10 ), + viewId = createMenu( tr( "MEN_VIEW" ), -1, 2 ); createMenu( separator(), fileId ); int importId = createMenu( tr( "MEN_IMPORT" ), fileId, -1, 10 ), exportId = createMenu( tr( "MEN_EXPORT" ), fileId, -1, 10 ), + nodeId = createMenu( tr( "MEN_NODE_CTRL" ), ctrlId, -1, 10 ), + edgeId = createMenu( tr( "MEN_EDGE_CTRL" ), ctrlId, -1, 10 ), + faceId = createMenu( tr( "MEN_FACE_CTRL" ), ctrlId, -1, 10 ), + volumeId = createMenu( tr( "MEN_VOLUME_CTRL" ), ctrlId, -1, 10 ), addId = createMenu( tr( "MEN_ADD" ), modifyId, 402 ), removeId = createMenu( tr( "MEN_REMOVE" ), modifyId, 403 ), renumId = createMenu( tr( "MEN_RENUM" ), modifyId, 404 ), @@ -3103,30 +3363,29 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( 813, meshId, -1 ); createMenu( separator(), meshId, -1 ); createMenu( 900, meshId, -1 ); - createMenu( 902, meshId, -1 ); + //createMenu( 902, meshId, -1 ); createMenu( 903, meshId, -1 ); createMenu( 904, meshId, -1 ); createMenu( separator(), meshId, -1 ); - createMenu( 6003, ctrlId, -1 ); - createMenu( 6001, ctrlId, -1 ); - createMenu( 6004, ctrlId, -1 ); - createMenu( separator(), ctrlId, -1 ); - createMenu( 6005, ctrlId, -1 ); - createMenu( 6002, ctrlId, -1 ); - createMenu( 6018, ctrlId, -1 ); - createMenu( 6019, ctrlId, -1 ); - createMenu( 6011, ctrlId, -1 ); - createMenu( 6012, ctrlId, -1 ); - createMenu( 6013, ctrlId, -1 ); - createMenu( 6014, ctrlId, -1 ); - createMenu( 6015, ctrlId, -1 ); - createMenu( 6016, ctrlId, -1 ); - createMenu( separator(), ctrlId, -1 ); - createMenu( 6017, ctrlId, -1 ); - createMenu( 6009, ctrlId, -1 ); - createMenu( 6021, ctrlId, -1 ); - createMenu( separator(), ctrlId, -1 ); + createMenu( 6005, nodeId, -1 ); + createMenu( 6002, edgeId, -1 ); + createMenu( 6003, edgeId, -1 ); + createMenu( 6001, edgeId, -1 ); + createMenu( 6004, edgeId, -1 ); + createMenu( 6021, faceId, -1 ); + createMenu( 6018, faceId, -1 ); + createMenu( 6019, faceId, -1 ); + createMenu( 6011, faceId, -1 ); + createMenu( 6012, faceId, -1 ); + createMenu( 6013, faceId, -1 ); + createMenu( 6014, faceId, -1 ); + createMenu( 6015, faceId, -1 ); + createMenu( 6016, faceId, -1 ); + createMenu( 6022, faceId, -1 ); + createMenu( 6017, volumeId, -1 ); + createMenu( 6009, volumeId, -1 ); + createMenu( 6023, volumeId, -1 ); createMenu( 4000, addId, -1 ); createMenu( 4009, addId, -1 ); @@ -3148,6 +3407,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( 4041, removeId, -1 ); createMenu( 4042, removeId, -1 ); + createMenu( 4044, removeId, -1 ); + createMenu( separator(), removeId, -1 ); createMenu( 4043, removeId, -1 ); createMenu( 4051, renumId, -1 ); @@ -3160,8 +3421,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( 4065, transfId, -1 ); createMenu( 4066, transfId, -1 ); createMenu( 4068, transfId, -1 ); + createMenu( 4069, transfId, -1 ); - createMenu( 406, modifyId, -1 ); createMenu( 4067,modifyId, -1 ); createMenu( 407, modifyId, -1 ); createMenu( 408, modifyId, -1 ); @@ -3177,6 +3438,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( 417, modifyId, -1 ); createMenu( 418, modifyId, -1 ); + createMenu( 501, measureId, -1 ); + createMenu( 502, measureId, -1 ); createMenu( 214, viewId, -1 ); // ----- create toolbars -------------- @@ -3203,17 +3466,19 @@ void SMESHGUI::initialize( CAM_Application* app ) //createTool( 815, meshTb ); createTool( separator(), meshTb ); createTool( 900, meshTb ); - createTool( 902, meshTb ); + //createTool( 902, meshTb ); createTool( 903, meshTb ); createTool( 904, meshTb ); createTool( separator(), meshTb ); - createTool( 6001, ctrlTb ); + createTool( 6005, ctrlTb ); + createTool( separator(), ctrlTb ); + createTool( 6002, ctrlTb ); createTool( 6003, ctrlTb ); + createTool( 6001, ctrlTb ); createTool( 6004, ctrlTb ); createTool( separator(), ctrlTb ); - createTool( 6005, ctrlTb ); - createTool( 6002, ctrlTb ); + createTool( 6021, ctrlTb ); createTool( 6018, ctrlTb ); createTool( 6019, ctrlTb ); createTool( 6011, ctrlTb ); @@ -3222,10 +3487,11 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( 6014, ctrlTb ); createTool( 6015, ctrlTb ); createTool( 6016, ctrlTb ); + createTool( 6022, ctrlTb ); createTool( separator(), ctrlTb ); createTool( 6017, ctrlTb ); createTool( 6009, ctrlTb ); - createTool( 6021, ctrlTb ); + createTool( 6023, ctrlTb ); createTool( separator(), ctrlTb ); createTool( 4000, addRemTb ); @@ -3248,6 +3514,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( separator(), addRemTb ); createTool( 4041, addRemTb ); createTool( 4042, addRemTb ); + createTool( 4044, addRemTb ); createTool( 4043, addRemTb ); createTool( separator(), addRemTb ); createTool( 4051, addRemTb ); @@ -3260,9 +3527,9 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( 4065, addRemTb ); createTool( 4066, addRemTb ); createTool( 4068, addRemTb ); + createTool( 4069, addRemTb ); createTool( separator(), addRemTb ); - createTool( 406, modifyTb ); createTool( 4067,modifyTb ); createTool( 407, modifyTb ); createTool( 408, modifyTb ); @@ -3332,7 +3599,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createPopupItem( 713, OB, mesh, "&& isComputable" ); // MESH ORDER createPopupItem( 214, OB, mesh_group ); // UPDATE createPopupItem( 900, OB, mesh_group ); // ADV_INFO - createPopupItem( 902, OB, mesh ); // STD_INFO + //createPopupItem( 902, OB, mesh ); // STD_INFO createPopupItem( 903, OB, mesh_group ); // WHAT_IS createPopupItem( 904, OB, mesh_group ); // FIND_ELEM popupMgr()->insert( separator(), -1, 0 ); @@ -3368,7 +3635,7 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->insert( separator(), -1, 0 ); createPopupItem( 214, View, mesh_group ); // UPDATE createPopupItem( 900, View, mesh_group ); // ADV_INFO - createPopupItem( 902, View, mesh ); // STD_INFO + //createPopupItem( 902, View, mesh ); // STD_INFO createPopupItem( 903, View, mesh_group ); // WHAT_IS createPopupItem( 904, View, mesh_group ); // FIND_ELEM popupMgr()->insert( separator(), -1, 0 ); @@ -3456,12 +3723,12 @@ void SMESHGUI::initialize( CAM_Application* app ) //------------------------------------------------- // Representation of the 2D Quadratic elements - //------------------------------------------------- + //------------------------------------------------- anId = popupMgr()->insert( tr( "MEN_QUADRATIC_REPRESENT" ), -1, -1 ); popupMgr()->insert( action( 231 ), anId, -1 ); // LINE REPRESENTATION popupMgr()->setRule( action( 231 ), aMeshInVTK + "and isVisible",QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 231 ), "quadratic2DMode = 'eLines'", QtxPopupMgr::ToggleRule ); - + popupMgr()->insert( action( 232 ), anId, -1 ); // ARC REPRESENTATION popupMgr()->setRule( action( 232 ), aMeshInVTK + "and isVisible", QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 232 ), "quadratic2DMode = 'eArcs'", QtxPopupMgr::ToggleRule ); @@ -3485,14 +3752,6 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->insert( action( 1133 ), -1, -1 ); popupMgr()->setRule( action( 1133 ), aMeshInVTK + "&& isVisible", QtxPopupMgr::VisibleRule ); - //------------------------------------------------- - // Clipping - //------------------------------------------------- - popupMgr()->insert( action( 1134 ), -1, -1 ); - popupMgr()->setRule( action( 1134 ), aMeshInVTK + "&& selcount=1 && isVisible", QtxPopupMgr::VisibleRule ); - - popupMgr()->insert( separator(), -1, -1 ); - //------------------------------------------------- // Controls //------------------------------------------------- @@ -3503,88 +3762,110 @@ void SMESHGUI::initialize( CAM_Application* app ) aMeshInVtkHasVolumes = aMeshInVTK + "&&" + hasVolumes; anId = popupMgr()->insert( tr( "MEN_CTRL" ), -1, -1 ); - + popupMgr()->insert( action( 200 ), anId, -1 ); // RESET popupMgr()->setRule( action( 200 ), aMeshInVTK + "&& controlMode <> 'eNone'", QtxPopupMgr::VisibleRule ); popupMgr()->insert( separator(), anId, -1 ); - popupMgr()->insert( action( 6003 ), anId, -1 ); // FREE_BORDER + int aSubId = popupMgr()->insert( tr( "MEN_NODE_CTRL" ), anId, -1 ); // NODE CONTROLS + + popupMgr()->insert( action( 6005 ), aSubId, -1 ); // FREE_NODE + popupMgr()->setRule( action( 6005 ), aMeshInVtkHasNodes, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6005 ), "controlMode = 'eFreeNodes'", QtxPopupMgr::ToggleRule ); + + aSubId = popupMgr()->insert( tr( "MEN_EDGE_CTRL" ), anId, -1 ); // EDGE CONTROLS + + popupMgr()->insert( action( 6002 ), aSubId, -1 ); // FREE_EDGE + popupMgr()->setRule( action( 6002 ), aMeshInVtkHasEdges, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6002 ), "controlMode = 'eFreeEdges'", QtxPopupMgr::ToggleRule ); + + popupMgr()->insert( action( 6003 ), aSubId, -1 ); // FREE_BORDER popupMgr()->setRule( action( 6003 ), aMeshInVtkHasEdges, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6003 ), "controlMode = 'eFreeBorders'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6001 ), anId, -1 ); // LENGTH + popupMgr()->insert( action( 6001 ), aSubId, -1 ); // LENGTH popupMgr()->setRule( action( 6001 ), aMeshInVtkHasEdges, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6001 ), "controlMode = 'eLength'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6004 ), anId, -1 ); // CONNECTION + popupMgr()->insert( action( 6004 ), aSubId, -1 ); // CONNECTION popupMgr()->setRule( action( 6004 ), aMeshInVtkHasEdges, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6004 ), "controlMode = 'eMultiConnection'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( separator(), anId, -1 ); + aSubId = popupMgr()->insert( tr( "MEN_FACE_CTRL" ), anId, -1 ); // FACE CONTROLS - popupMgr()->insert( action( 6005 ), anId, -1 ); // FREE_NODE - popupMgr()->setRule( action( 6005 ), aMeshInVtkHasNodes, QtxPopupMgr::VisibleRule ); - popupMgr()->setRule( action( 6005 ), "controlMode = 'eFreeNodes'", QtxPopupMgr::ToggleRule ); - - popupMgr()->insert( action( 6002 ), anId, -1 ); // FREE_EDGE - popupMgr()->setRule( action( 6002 ), aMeshInVtkHasEdges, QtxPopupMgr::VisibleRule ); - popupMgr()->setRule( action( 6002 ), "controlMode = 'eFreeEdges'", QtxPopupMgr::ToggleRule ); + popupMgr()->insert( action( 6021 ), aSubId, -1 ); // FREE_FACE + popupMgr()->setRule( action( 6021 ), aMeshInVtkHasFaces /*aMeshInVtkHasVolumes*/, + QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6021 ), "controlMode = 'eFreeFaces'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6018 ), anId, -1 ); // LENGTH_2D + popupMgr()->insert( action( 6018 ), aSubId, -1 ); // LENGTH_2D popupMgr()->setRule( action( 6018 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6018 ), "controlMode = 'eLength2D'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6019 ), anId, -1 ); // CONNECTION_2D + popupMgr()->insert( action( 6019 ), aSubId, -1 ); // CONNECTION_2D popupMgr()->setRule( action( 6019 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6019 ), "controlMode = 'eMultiConnection2D'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6011 ), anId, -1 ); // AREA + popupMgr()->insert( action( 6011 ), aSubId, -1 ); // AREA popupMgr()->setRule( action( 6011 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6011 ), "controlMode = 'eArea'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6012 ), anId, -1 ); // TAPER + popupMgr()->insert( action( 6012 ), aSubId, -1 ); // TAPER popupMgr()->setRule( action( 6012 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6012 ), "controlMode = 'eTaper'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6013 ), anId, -1 ); // ASPECT + popupMgr()->insert( action( 6013 ), aSubId, -1 ); // ASPECT popupMgr()->setRule( action( 6013 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6013 ), "controlMode = 'eAspectRatio'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6014 ), anId, -1 ); // MIN_ANG + popupMgr()->insert( action( 6014 ), aSubId, -1 ); // MIN_ANG popupMgr()->setRule( action( 6014 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6014 ), "controlMode = 'eMinimumAngle'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6015 ), anId, -1 ); // WARP + popupMgr()->insert( action( 6015 ), aSubId, -1 ); // WARP popupMgr()->setRule( action( 6015 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6015 ), "controlMode = 'eWarping'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6016 ), anId, -1 ); // SKEW + popupMgr()->insert( action( 6016 ), aSubId, -1 ); // SKEW popupMgr()->setRule( action( 6016 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6016 ), "controlMode = 'eSkew'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( separator(), anId, -1 ); + popupMgr()->insert( action( 6022 ), aSubId, -1 ); // MAX_ELEMENT_LENGTH_2D + popupMgr()->setRule( action( 6022 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6022 ), "controlMode = 'eMaxElementLength2D'", QtxPopupMgr::ToggleRule ); + + aSubId = popupMgr()->insert( tr( "MEN_VOLUME_CTRL" ), anId, -1 ); // VOLUME CONTROLS - popupMgr()->insert( action( 6017 ), anId, -1 ); // ASPECT_3D + popupMgr()->insert( action( 6017 ), aSubId, -1 ); // ASPECT_3D popupMgr()->setRule( action( 6017 ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6017 ), "controlMode = 'eAspectRatio3D'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert ( action( 6009 ), anId, -1 ); // VOLUME_3D + popupMgr()->insert ( action( 6009 ), aSubId, -1 ); // VOLUME_3D popupMgr()->setRule( action( 6009 ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6009 ), "controlMode = 'eVolume3D'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6021 ), anId, -1 ); // FREE_FACE - popupMgr()->setRule( action( 6021 ), aMeshInVtkHasFaces /*aMeshInVtkHasVolumes*/, - QtxPopupMgr::VisibleRule ); - popupMgr()->setRule( action( 6021 ), "controlMode = 'eFreeFaces'", QtxPopupMgr::ToggleRule ); + popupMgr()->insert( action( 6023 ), aSubId, -1 ); // MAX_ELEMENT_LENGTH_3D + popupMgr()->setRule( action( 6023 ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6023 ), "controlMode = 'eMaxElementLength3D'", QtxPopupMgr::ToggleRule ); popupMgr()->insert( separator(), anId, -1 ); popupMgr()->insert( action( 201 ), anId, -1 ); // SCALAR_BAR_PROP popupMgr()->setRule( action( 201 ), aMeshInVTK + "&& controlMode <> 'eNone'", QtxPopupMgr::VisibleRule ); + popupMgr()->insert( separator(), anId, -1 ); + + popupMgr()->insert( action( 202 ), anId, -1 ); // SAVE_DISTRIBUTION + popupMgr()->setRule( action( 202 ), aMeshInVTK + "&& isNumFunctor", QtxPopupMgr::VisibleRule ); + + popupMgr()->insert( action( 203 ), anId, -1 ); // SHOW_DISTRIBUTION + popupMgr()->setRule( action( 203 ), aMeshInVTK + "&& isNumFunctor", QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 203 ), aMeshInVTK + "&& isNumFunctor && isDistributionVisible", QtxPopupMgr::ToggleRule); + + popupMgr()->insert( separator(), -1, -1 ); - + //------------------------------------------------- // Display / Erase //------------------------------------------------- @@ -3601,8 +3882,19 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->insert( separator(), -1, -1 ); + //------------------------------------------------- + // Clipping + //------------------------------------------------- + popupMgr()->insert( action( 1134 ), -1, -1 ); + popupMgr()->setRule( action( 1134 ), "client='VTKViewer'", QtxPopupMgr::VisibleRule ); + + popupMgr()->insert( separator(), -1, -1 ); + connect( application(), SIGNAL( viewManagerActivated( SUIT_ViewManager* ) ), this, SLOT( onViewManagerActivated( SUIT_ViewManager* ) ) ); + + connect( application(), SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ), + this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ) ); } //================================================================================ @@ -3634,7 +3926,7 @@ bool SMESHGUI::reusableOperation( const int id ) { // compute, evaluate and precompute are not reusable operations return ( id == 701 || id == 711 || id == 712 ) ? false : SalomeApp_Module::reusableOperation( id ); -} +} bool SMESHGUI::activateModule( SUIT_Study* study ) { @@ -3643,6 +3935,21 @@ bool SMESHGUI::activateModule( SUIT_Study* study ) setMenuShown( true ); setToolShown( true ); + // import Python module that manages SMESH plugins (need to be here because SalomePyQt API uses active module) + PyGILState_STATE gstate = PyGILState_Ensure(); + PyObject* pluginsmanager=PyImport_ImportModule((char*)"salome_pluginsmanager"); + if(pluginsmanager==NULL) + PyErr_Print(); + else + { + PyObject* result=PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",1,"smesh",tr("MEN_MESH").toStdString().c_str(),tr("SMESH_PLUGINS_OTHER").toStdString().c_str()); + if(result==NULL) + PyErr_Print(); + Py_XDECREF(result); + } + PyGILState_Release(gstate); + // end of GEOM plugins loading + // Reset actions accelerator keys action(111)->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B)); // Import DAT action(112)->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U)); // Import UNV @@ -3759,13 +4066,60 @@ void SMESHGUI::onViewManagerActivated( SUIT_ViewManager* mgr ) SMESH::UpdateSelectionProp( this ); } +void SMESHGUI::onViewManagerRemoved( SUIT_ViewManager* theViewManager ) +{ + if( theViewManager && theViewManager->getType() == SVTK_Viewer::Type() ) + myClippingPlaneInfoMap.erase( theViewManager ); +} + +void SMESHGUI::addActorAsObserver( SMESH_Actor* theActor ) +{ + theActor->AddObserver( SMESH::DeleteActorEvent, + myEventCallbackCommand.GetPointer(), + myPriority ); +} + +void SMESHGUI::ProcessEvents( vtkObject* theObject, + unsigned long theEvent, + void* theClientData, + void* theCallData ) +{ + if( SMESHGUI* aSMESHGUI = reinterpret_cast( theClientData ) ) { + if( theObject && theEvent == SMESH::DeleteActorEvent ) { + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( theObject ) ) { + SMESHGUI_ClippingPlaneInfoMap& aClippingPlaneInfoMap = aSMESHGUI->getClippingPlaneInfoMap(); + SMESHGUI_ClippingPlaneInfoMap::iterator anIter1 = aClippingPlaneInfoMap.begin(); + for( ; anIter1 != aClippingPlaneInfoMap.end(); anIter1++ ) { + SMESHGUI_ClippingPlaneInfoList& aClippingPlaneInfoList = anIter1->second; + SMESHGUI_ClippingPlaneInfoList::iterator anIter2 = aClippingPlaneInfoList.begin(); + for( ; anIter2 != aClippingPlaneInfoList.end(); anIter2++ ) { + SMESH::ClippingPlaneInfo& aClippingPlaneInfo = *anIter2; + std::list& anActorList = aClippingPlaneInfo.ActorList; + SMESH::TActorList::iterator anIter3 = anActorList.begin(); + for ( ; anIter3 != anActorList.end(); anIter3++ ) { + if( anActor == *anIter3 ) { + anActorList.erase( anIter3 ); + break; + } + } + } + } + } + } + } +} + void SMESHGUI::createPreferences() { // General tab ------------------------------------------------------------------------ int genTab = addPreference( tr( "PREF_TAB_GENERAL" ) ); - int updateGroup = addPreference( tr( "PREF_GROUP_UPDATE" ), genTab ); - addPreference( tr( "PREF_AUTO_UPDATE" ), updateGroup, LightApp_Preferences::Bool, "SMESH", "auto_update" ); + int autoUpdate = addPreference( tr( "PREF_AUTO_UPDATE" ), genTab, LightApp_Preferences::Auto, "SMESH", "auto_update" ); + int lim = addPreference( tr( "PREF_UPDATE_LIMIT" ), autoUpdate, LightApp_Preferences::IntSpin, "SMESH", "update_limit" ); + setPreferenceProperty( lim, "min", 0 ); + setPreferenceProperty( lim, "max", 100000000 ); + setPreferenceProperty( lim, "step", 1000 ); + setPreferenceProperty( lim, "special", tr( "PREF_UPDATE_LIMIT_NOLIMIT" ) ); int qaGroup = addPreference( tr( "PREF_GROUP_QUALITY" ), genTab ); setPreferenceProperty( qaGroup, "columns", 2 ); @@ -3807,8 +4161,8 @@ void SMESHGUI::createPreferences() "SMESH", "max_angle" ); setPreferenceProperty( maxAngle, "min", 1 ); setPreferenceProperty( maxAngle, "max", 90 ); - - + + int exportgroup = addPreference( tr( "PREF_GROUP_EXPORT" ), genTab ); setPreferenceProperty( exportgroup, "columns", 2 ); @@ -3819,9 +4173,9 @@ void SMESHGUI::createPreferences() setPreferenceProperty( computeGroup, "columns", 2 ); int notifyMode = addPreference( tr( "PREF_NOTIFY_MODE" ), computeGroup, LightApp_Preferences::Selector, "SMESH", "show_result_notification" ); modes.clear(); - modes.append( "Never" ); - modes.append( "Errors only" ); - modes.append( "Always" ); + modes.append( tr( "PREF_NOTIFY_NEVER" ) ); + modes.append( tr( "PREF_NOTIFY_ERROR" ) ); + modes.append( tr( "PREF_NOTIFY_ALWAYS" ) ); indices.clear(); indices.append( 0 ); indices.append( 1 ); @@ -3829,6 +4183,18 @@ void SMESHGUI::createPreferences() setPreferenceProperty( notifyMode, "strings", modes ); setPreferenceProperty( notifyMode, "indexes", indices ); + int infoGroup = addPreference( tr( "PREF_GROUP_INFO" ), genTab ); + setPreferenceProperty( computeGroup, "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" ) ); + modes.append( tr( "PREF_ELEM_INFO_TREE" ) ); + indices.clear(); + indices.append( 0 ); + indices.append( 1 ); + setPreferenceProperty( elemInfo, "strings", modes ); + setPreferenceProperty( elemInfo, "indexes", indices ); + int segGroup = addPreference( tr( "PREF_GROUP_SEGMENT_LENGTH" ), genTab ); setPreferenceProperty( segGroup, "columns", 2 ); int segLen = addPreference( tr( "PREF_SEGMENT_LENGTH" ), segGroup, LightApp_Preferences::IntSpin, @@ -3839,15 +4205,15 @@ void SMESHGUI::createPreferences() "SMESH", "nb_segments_per_edge" ); setPreferenceProperty( nbSeg, "min", 1 ); setPreferenceProperty( nbSeg, "max", 10000000 ); - + // Quantities with individual precision settings int precGroup = addPreference( tr( "SMESH_PREF_GROUP_PRECISION" ), genTab ); setPreferenceProperty( precGroup, "columns", 2 ); - + const int nbQuantities = 6; int precs[nbQuantities], ii = 0; precs[ii++] = addPreference( tr( "SMESH_PREF_length_precision" ), precGroup, - LightApp_Preferences::IntSpin, "SMESH", "length_precision" ); + LightApp_Preferences::IntSpin, "SMESH", "length_precision" ); precs[ii++] = addPreference( tr( "SMESH_PREF_angle_precision" ), precGroup, LightApp_Preferences::IntSpin, "SMESH", "angle_precision" ); precs[ii++] = addPreference( tr( "SMESH_PREF_len_tol_precision" ), precGroup, @@ -3857,14 +4223,14 @@ void SMESHGUI::createPreferences() precs[ii++] = addPreference( tr( "SMESH_PREF_area_precision" ), precGroup, LightApp_Preferences::IntSpin, "SMESH", "area_precision" ); precs[ii ] = addPreference( tr( "SMESH_PREF_vol_precision" ), precGroup, - LightApp_Preferences::IntSpin, "SMESH", "vol_precision" ); - + LightApp_Preferences::IntSpin, "SMESH", "vol_precision" ); + // Set property for precision value for spinboxes for ( ii = 0; ii < nbQuantities; ii++ ){ setPreferenceProperty( precs[ii], "min", -14 ); setPreferenceProperty( precs[ii], "max", 14 ); setPreferenceProperty( precs[ii], "precision", 2 ); - } + } // Mesh tab ------------------------------------------------------------------------ int meshTab = addPreference( tr( "PREF_TAB_MESH" ) ); @@ -3906,6 +4272,11 @@ void SMESHGUI::createPreferences() addPreference( tr( "PREF_BACKFACE" ), elemGroup, LightApp_Preferences::Color, "SMESH", "backface_color" ); addPreference( tr( "PREF_COLOR_0D" ), elemGroup, LightApp_Preferences::Color, "SMESH", "elem0d_color" ); + int grpGroup = addPreference( tr( "PREF_GROUP_GROUPS" ), meshTab ); + setPreferenceProperty( grpGroup, "columns", 2 ); + + addPreference( tr( "PREF_GRP_NAMES" ), grpGroup, LightApp_Preferences::Color, "SMESH", "group_name_color" ); + //int sp = addPreference( "", elemGroup, LightApp_Preferences::Space ); //setPreferenceProperty( sp, "hstretch", 0 ); //setPreferenceProperty( sp, "vstretch", 0 ); @@ -4043,6 +4414,18 @@ void SMESHGUI::createPreferences() setPreferenceProperty( hh, "min", 0.0 ); setPreferenceProperty( hh, "max", 1.0 ); setPreferenceProperty( hh, "step", 0.1 ); + + int distributionGr = addPreference( tr( "SMESH_DISTRIBUTION_SCALARBAR" ), sbarTab, LightApp_Preferences::Auto, "SMESH", "distribution_visibility" ); + int coloringType = addPreference( tr( "SMESH_DISTRIBUTION_COLORING_TYPE" ), distributionGr, LightApp_Preferences::Selector, "SMESH", "distribution_coloring_type" ); + setPreferenceProperty( distributionGr, "columns", 3 ); + QStringList types; + types.append( tr( "SMESH_MONOCOLOR" ) ); + types.append( tr( "SMESH_MULTICOLOR" ) ); + indices.clear(); indices.append( 0 ); indices.append( 1 ); + setPreferenceProperty( coloringType, "strings", types ); + setPreferenceProperty( coloringType, "indexes", indices ); + addPreference( tr( "SMESH_DISTRIBUTION_COLOR" ), distributionGr, LightApp_Preferences::Color, "SMESH", "distribution_color" ); + } void SMESHGUI::preferencesChanged( const QString& sect, const QString& name ) @@ -4262,12 +4645,9 @@ SALOMEDS::Color SMESHGUI::getUniqueColor( const QList& theReser if( aTolerance < 1 ) break; } - //cout << "Iteration N" << anIterations << " (tolerance=" << aTolerance << ")"<< endl; aHue = (int)( 360.0 * rand() / RAND_MAX ); - //cout << "Hue = " << aHue << endl; - //cout << "Auto colors : "; bool ok = true; QList::const_iterator it = theReservedColors.constBegin(); QList::const_iterator itEnd = theReservedColors.constEnd(); @@ -4278,21 +4658,17 @@ SALOMEDS::Color SMESHGUI::getUniqueColor( const QList& theReser int h, s, v; aQColor.getHsv( &h, &s, &v ); - //cout << h << " "; if( abs( h - aHue ) < aTolerance ) { ok = false; - //cout << "break (diff = " << abs( h - aHue ) << ")"; break; } } - //cout << endl; if( ok ) break; } - //cout << "Hue of the returned color = " << aHue << endl; QColor aColor; aColor.setHsv( aHue, 255, 255 ); @@ -4380,6 +4756,37 @@ void SMESHGUI::storeVisualParameters (int savePoint) // saving VTK actors properties if (vType == SVTK_Viewer::Type()) { + // store the clipping planes attached to the view manager + SMESHGUI_ClippingPlaneInfoList aClippingPlaneInfoList; + SMESHGUI_ClippingPlaneInfoMap::const_iterator anIter = myClippingPlaneInfoMap.find( vman ); + if( anIter != myClippingPlaneInfoMap.end() ) + aClippingPlaneInfoList = anIter->second; + + if( !aClippingPlaneInfoList.empty() ) { + SMESHGUI_ClippingPlaneInfoList::const_iterator anIter = aClippingPlaneInfoList.begin(); + for( int anId = 0; anIter != aClippingPlaneInfoList.end(); anIter++, anId++ ) + { + const SMESH::ClippingPlaneInfo& aClippingPlaneInfo = *anIter; + SMESH::OrientedPlane* aPlane = aClippingPlaneInfo.Plane; + + QString aPropertyName( "ClippingPlane" ); + aPropertyName += gSeparator; + aPropertyName += QString::number( vtkViewers ); + aPropertyName += gSeparator; + aPropertyName += QString::number( anId ); + + QString aPropertyValue = QString::number( (int)aPlane->GetOrientation() ).toLatin1().constData(); + aPropertyValue += gDigitsSep; + aPropertyValue += QString::number( aPlane->GetDistance() ).toLatin1().constData(); + aPropertyValue += gDigitsSep; + aPropertyValue += QString::number( aPlane->myAngle[0] ).toLatin1().constData(); + aPropertyValue += gDigitsSep; + aPropertyValue += QString::number( aPlane->myAngle[1] ).toLatin1().constData(); + + ip->setProperty( aPropertyName.toStdString(), aPropertyValue.toStdString() ); + } + } + QVector views = vman->getViews(); for (int i = 0, iEnd = vman->getViewsCount(); i < iEnd; i++) { @@ -4505,22 +4912,25 @@ void SMESHGUI::storeVisualParameters (int savePoint) // Clipping param = vtkParam + "ClippingPlane"; - int nPlanes = aSmeshActor->GetNumberOfClippingPlanes(); - if (!nPlanes) - ip->setParameter(entry, param, "Off"); - for (int ipl = 0; ipl < nPlanes; ipl++) { - //vtkPlane* plane = aSmeshActor->GetClippingPlane(ipl); - SMESH::Orientation anOrientation; - double aDistance; - vtkFloatingPointType anAngle[2]; - SMESHGUI_ClippingDlg::GetPlaneParam(aSmeshActor, ipl, anOrientation, aDistance, anAngle); - std::string planeValue = QString::number((int)anOrientation).toLatin1().data(); - planeValue += gDigitsSep; planeValue += QString::number(aDistance).toLatin1().data(); - planeValue += gDigitsSep; planeValue += QString::number(anAngle[0]).toLatin1().data(); - planeValue += gDigitsSep; planeValue += QString::number(anAngle[1]).toLatin1().data(); - - ip->setParameter(entry, param + QString::number(ipl+1).toLatin1().data(), planeValue); + int aPlaneId = 0; + if( !aClippingPlaneInfoList.empty() ) { + SMESHGUI_ClippingPlaneInfoList::const_iterator anIter1 = aClippingPlaneInfoList.begin(); + for( int anId = 0; anIter1 != aClippingPlaneInfoList.end(); anIter1++, anId++ ) + { + const SMESH::ClippingPlaneInfo& aClippingPlaneInfo = *anIter1; + std::list anActorList = aClippingPlaneInfo.ActorList; + SMESH::TActorList::iterator anIter2 = anActorList.begin(); + for ( ; anIter2 != anActorList.end(); anIter2++ ) { + if( aSmeshActor == *anIter2 ) { + ip->setParameter( entry, param + QString::number( ++aPlaneId ).toLatin1().constData(), + QString::number( anId ).toLatin1().constData() ); + break; + } + } + } } + if( aPlaneId == 0 ) + ip->setParameter( entry, param, "Off" ); } // if (io->hasEntry()) } // SMESH_Actor && hasIO } // isVisible @@ -4532,6 +4942,25 @@ void SMESHGUI::storeVisualParameters (int savePoint) } // for (viewManagers) } +// data structures for clipping planes processing +typedef struct { + int Id; + vtkIdType Orientation; + vtkFloatingPointType Distance; + vtkFloatingPointType Angle[2]; +} TPlaneData; +typedef std::list TPlaneDataList; +typedef std::map TPlaneDataMap; + +typedef std::list TActorList; +typedef struct { + int PlaneId; + TActorList ActorList; + SUIT_ViewManager* ViewManager; +} TPlaneInfo; +typedef std::list TPlaneInfoList; +typedef std::map TPlaneInfoMap; + /*! * \brief Restore visual parameters * @@ -4556,8 +4985,9 @@ void SMESHGUI::restoreVisualParameters (int savePoint) savePoint); _PTR(IParameters) ip = ClientFactory::getIParameters(ap); - // restore map of custom markers + // restore map of custom markers and map of clipping planes VTK::MarkerMap& aMarkerMap = myMarkerMap[ studyDS->StudyId() ]; + TPlaneDataMap aPlaneDataMap; std::vector properties = ip->getProperties(); for (std::vector::iterator propIt = properties.begin(); propIt != properties.end(); ++propIt) @@ -4567,52 +4997,103 @@ void SMESHGUI::restoreVisualParameters (int savePoint) QString aPropertyValue( ip->getProperty( property ).c_str() ); QStringList aPropertyNameList = aPropertyName.split( gSeparator, QString::SkipEmptyParts ); - if( aPropertyNameList.size() != 2 ) + if( aPropertyNameList.isEmpty() ) continue; - int anId = 0; - bool ok = false; - if( aPropertyNameList[0] == "texture" ) - anId = aPropertyNameList[1].toInt( &ok ); + QString aPropertyType = aPropertyNameList[0]; + if( aPropertyType == "texture" ) + { + if( aPropertyNameList.size() != 2 ) + continue; - if( !ok || anId < 1 ) - continue; + bool ok = false; + int anId = aPropertyNameList[1].toInt( &ok ); + if( !ok || anId < 1 ) + continue; - QStringList aPropertyValueList = aPropertyValue.split( gPathSep, QString::SkipEmptyParts ); - if( aPropertyValueList.size() != 2 ) - continue; + QStringList aPropertyValueList = aPropertyValue.split( gPathSep, QString::SkipEmptyParts ); + if( aPropertyValueList.size() != 2 ) + continue; - std::string aMarkerFileName = aPropertyValueList[0].toStdString(); - QString aMarkerTextureString = aPropertyValueList[1]; - QStringList aMarkerTextureStringList = aMarkerTextureString.split( gDigitsSep, QString::SkipEmptyParts ); - if( aMarkerTextureStringList.size() != 3 ) - continue; + std::string aMarkerFileName = aPropertyValueList[0].toStdString(); + QString aMarkerTextureString = aPropertyValueList[1]; + QStringList aMarkerTextureStringList = aMarkerTextureString.split( gDigitsSep, QString::SkipEmptyParts ); + if( aMarkerTextureStringList.size() != 3 ) + continue; - ok = false; - ushort aWidth = aMarkerTextureStringList[0].toUShort( &ok ); - if( !ok ) - continue; + ok = false; + ushort aWidth = aMarkerTextureStringList[0].toUShort( &ok ); + if( !ok ) + continue; - ok = false; - ushort aHeight = aMarkerTextureStringList[1].toUShort( &ok ); - if( !ok ) - continue; + ok = false; + ushort aHeight = aMarkerTextureStringList[1].toUShort( &ok ); + if( !ok ) + continue; - VTK::MarkerTexture aMarkerTexture; - aMarkerTexture.push_back( aWidth ); - aMarkerTexture.push_back( aHeight ); + VTK::MarkerTexture aMarkerTexture; + aMarkerTexture.push_back( aWidth ); + aMarkerTexture.push_back( aHeight ); - QString aMarkerTextureData = aMarkerTextureStringList[2]; - for( int i = 0, n = aMarkerTextureData.length(); i < n; i++ ) - { - QChar aChar = aMarkerTextureData.at( i ); - if( aChar.isDigit() ) - aMarkerTexture.push_back( aChar.digitValue() ); + QString aMarkerTextureData = aMarkerTextureStringList[2]; + for( int i = 0, n = aMarkerTextureData.length(); i < n; i++ ) + { + QChar aChar = aMarkerTextureData.at( i ); + if( aChar.isDigit() ) + aMarkerTexture.push_back( aChar.digitValue() ); + } + + aMarkerMap[ anId ] = VTK::MarkerData( aMarkerFileName, aMarkerTexture ); } + else if( aPropertyType == "ClippingPlane" ) + { + if( aPropertyNameList.size() != 3 ) + continue; + + bool ok = false; + int aViewId = aPropertyNameList[1].toInt( &ok ); + if( !ok || aViewId < 0 ) + continue; + + ok = false; + int aClippingPlaneId = aPropertyNameList[2].toInt( &ok ); + if( !ok || aClippingPlaneId < 0 ) + continue; + + QStringList aPropertyValueList = aPropertyValue.split( gDigitsSep, QString::SkipEmptyParts ); + if( aPropertyValueList.size() != 4 ) + continue; + + TPlaneData aPlaneData; + aPlaneData.Id = aClippingPlaneId; + + ok = false; + aPlaneData.Orientation = aPropertyValueList[0].toInt( &ok ); + if( !ok ) + continue; + + ok = false; + aPlaneData.Distance = aPropertyValueList[1].toDouble( &ok ); + if( !ok ) + continue; - aMarkerMap[ anId ] = VTK::MarkerData( aMarkerFileName, aMarkerTexture ); + ok = false; + aPlaneData.Angle[0] = aPropertyValueList[2].toDouble( &ok ); + if( !ok ) + continue; + + ok = false; + aPlaneData.Angle[1] = aPropertyValueList[3].toDouble( &ok ); + if( !ok ) + continue; + + TPlaneDataList& aPlaneDataList = aPlaneDataMap[ aViewId ]; + aPlaneDataList.push_back( aPlaneData ); + } } + TPlaneInfoMap aPlaneInfoMap; + std::vector entries = ip->getEntries(); for (std::vector::iterator entIt = entries.begin(); entIt != entries.end(); ++entIt) @@ -4659,39 +5140,40 @@ void SMESHGUI::restoreVisualParameters (int savePoint) if (vtkActors.IsBound(viewIndex)) aSmeshActor = vtkActors.Find(viewIndex); + QList lst; + getApp()->viewManagers(viewerTypStr, lst); + + // SVTK ViewManager always has 1 ViewWindow, so view index is index of view manager + SUIT_ViewManager* vman = NULL; + if (viewIndex >= 0 && viewIndex < lst.count()) + vman = lst.at(viewIndex); + if (paramNameStr == "Visibility") { - if (!aSmeshActor && displayer()) + if (!aSmeshActor && displayer() && vman) { - QList lst; - getApp()->viewManagers(viewerTypStr, lst); - - // SVTK ViewManager always has 1 ViewWindow, so view index is index of view manager - if (viewIndex >= 0 && viewIndex < lst.count()) { - SUIT_ViewManager* vman = lst.at(viewIndex); - SUIT_ViewModel* vmodel = vman->getViewModel(); - // SVTK view model can be casted to SALOME_View - displayer()->Display(entry, true, dynamic_cast(vmodel)); - - // store displayed actor in a temporary map for quicker - // access later when restoring other parameters - SVTK_ViewWindow* vtkView = (SVTK_ViewWindow*) vman->getActiveView(); - vtkRenderer* Renderer = vtkView->getRenderer(); - VTK::ActorCollectionCopy aCopy(Renderer->GetActors()); - vtkActorCollection* theActors = aCopy.GetActors(); - theActors->InitTraversal(); - bool isFound = false; - vtkActor *ac = theActors->GetNextActor(); - for (; ac != NULL && !isFound; ac = theActors->GetNextActor()) { - if (ac->IsA("SMESH_Actor")) { - SMESH_Actor* aGeomAc = SMESH_Actor::SafeDownCast(ac); - if (aGeomAc->hasIO()) { - Handle(SALOME_InteractiveObject) io = - Handle(SALOME_InteractiveObject)::DownCast(aGeomAc->getIO()); - if (io->hasEntry() && strcmp(io->getEntry(), entry.toLatin1().data()) == 0) { - isFound = true; - vtkActors.Bind(viewIndex, aGeomAc); - } + SUIT_ViewModel* vmodel = vman->getViewModel(); + // SVTK view model can be casted to SALOME_View + displayer()->Display(entry, true, dynamic_cast(vmodel)); + + // store displayed actor in a temporary map for quicker + // access later when restoring other parameters + SVTK_ViewWindow* vtkView = (SVTK_ViewWindow*) vman->getActiveView(); + vtkRenderer* Renderer = vtkView->getRenderer(); + VTK::ActorCollectionCopy aCopy(Renderer->GetActors()); + vtkActorCollection* theActors = aCopy.GetActors(); + theActors->InitTraversal(); + bool isFound = false; + vtkActor *ac = theActors->GetNextActor(); + for (; ac != NULL && !isFound; ac = theActors->GetNextActor()) { + if (ac->IsA("SMESH_Actor")) { + SMESH_Actor* aGeomAc = SMESH_Actor::SafeDownCast(ac); + if (aGeomAc->hasIO()) { + Handle(SALOME_InteractiveObject) io = + Handle(SALOME_InteractiveObject)::DownCast(aGeomAc->getIO()); + if (io->hasEntry() && strcmp(io->getEntry(), entry.toLatin1().data()) == 0) { + isFound = true; + vtkActors.Bind(viewIndex, aGeomAc); } } } @@ -4808,14 +5290,16 @@ void SMESHGUI::restoreVisualParameters (int savePoint) } // Clipping else if (paramNameStr.startsWith("ClippingPlane")) { - cout << "$$$ ClippingPlane 1" << endl; - if (paramNameStr == "ClippingPlane1" || val == "Off") - aSmeshActor->RemoveAllClippingPlanes(); - if (val != "Off") { - cout << "$$$ ClippingPlane 2" << endl; - QStringList vals = val.split(gDigitsSep, QString::SkipEmptyParts); - if (vals.count() == 4) { // format check: 4 values - cout << "$$$ ClippingPlane 3" << endl; + QStringList vals = val.split(gDigitsSep, QString::SkipEmptyParts); + // old format - val looks like "Off" or "0:0.5:0:0" (orientation, distance, two angles) + // new format - val looks like "Off" or "0" (plane id) + // (note: in new format "Off" value is used only for consistency, + // so it is processed together with values in old format) + bool anIsOldFormat = ( vals.count() == 4 || val == "Off" ); + if( anIsOldFormat ) { + if (paramNameStr == "ClippingPlane1" || val == "Off") + aSmeshActor->RemoveAllClippingPlanes(); + if (val != "Off") { SMESH::Orientation anOrientation = (SMESH::Orientation)vals[0].toInt(); double aDistance = vals[1].toFloat(); vtkFloatingPointType anAngle[2]; @@ -4828,8 +5312,43 @@ void SMESHGUI::restoreVisualParameters (int savePoint) if (viewIndex >= 0 && viewIndex < lst.count()) { SUIT_ViewManager* vman = lst.at(viewIndex); SVTK_ViewWindow* vtkView = (SVTK_ViewWindow*) vman->getActiveView(); - SMESHGUI_ClippingDlg::AddPlane(aSmeshActor, vtkView, - anOrientation, aDistance, anAngle); + + SMESHGUI_ClippingPlaneInfoList& aClippingPlaneInfoList = myClippingPlaneInfoMap[ vman ]; + + SMESH::TActorList anActorList; + anActorList.push_back( aSmeshActor ); + SMESH::OrientedPlane* aPlane = + SMESHGUI_ClippingDlg::AddPlane(anActorList, vtkView, anOrientation, aDistance, anAngle); + if( aPlane ) { + SMESH::ClippingPlaneInfo aClippingPlaneInfo; + aClippingPlaneInfo.Plane = aPlane; + aClippingPlaneInfo.ActorList = anActorList; + aClippingPlaneInfoList.push_back( aClippingPlaneInfo ); + } + } + } + } + else { + bool ok = false; + int aPlaneId = val.toInt( &ok ); + if( ok && aPlaneId >= 0 ) { + bool anIsDefinedPlane = false; + TPlaneInfoList& aPlaneInfoList = aPlaneInfoMap[ viewIndex ]; + TPlaneInfoList::iterator anIter = aPlaneInfoList.begin(); + for( ; anIter != aPlaneInfoList.end(); anIter++ ) { + TPlaneInfo& aPlaneInfo = *anIter; + if( aPlaneInfo.PlaneId == aPlaneId ) { + aPlaneInfo.ActorList.push_back( aSmeshActor ); + anIsDefinedPlane = true; + break; + } + } + if( !anIsDefinedPlane ) { + TPlaneInfo aPlaneInfo; + aPlaneInfo.PlaneId = aPlaneId; + aPlaneInfo.ActorList.push_back( aSmeshActor ); + aPlaneInfo.ViewManager = vman; + aPlaneInfoList.push_back( aPlaneInfo ); } } } @@ -4840,6 +5359,55 @@ void SMESHGUI::restoreVisualParameters (int savePoint) } // for names/parameters iterator } // for entries iterator + // add clipping planes to actors according to the restored parameters + // and update the clipping plane map + TPlaneInfoMap::const_iterator anIter1 = aPlaneInfoMap.begin(); + for( ; anIter1 != aPlaneInfoMap.end(); anIter1++ ) { + int aViewId = anIter1->first; + const TPlaneInfoList& aPlaneInfoList = anIter1->second; + + TPlaneDataMap::const_iterator anIter2 = aPlaneDataMap.find( aViewId ); + if( anIter2 == aPlaneDataMap.end() ) + continue; + const TPlaneDataList& aPlaneDataList = anIter2->second; + + TPlaneInfoList::const_iterator anIter3 = aPlaneInfoList.begin(); + for( ; anIter3 != aPlaneInfoList.end(); anIter3++ ) { + const TPlaneInfo& aPlaneInfo = *anIter3; + int aPlaneId = aPlaneInfo.PlaneId; + const TActorList& anActorList = aPlaneInfo.ActorList; + SUIT_ViewManager* aViewManager = aPlaneInfo.ViewManager; + if( !aViewManager ) + continue; + + SVTK_ViewWindow* aViewWindow = dynamic_cast( aViewManager->getActiveView() ); + if( !aViewWindow ) + continue; + + SMESHGUI_ClippingPlaneInfoList& aClippingPlaneInfoList = myClippingPlaneInfoMap[ aViewManager ]; + + TPlaneDataList::const_iterator anIter4 = aPlaneDataList.begin(); + for( ; anIter4 != aPlaneDataList.end(); anIter4++ ) { + const TPlaneData& aPlaneData = *anIter4; + if( aPlaneData.Id == aPlaneId ) { + SMESH::OrientedPlane* aPlane = + SMESHGUI_ClippingDlg::AddPlane( anActorList, + aViewWindow, + (SMESH::Orientation)aPlaneData.Orientation, + aPlaneData.Distance, + aPlaneData.Angle ); + if( aPlane ) { + SMESH::ClippingPlaneInfo aClippingPlaneInfo; + aClippingPlaneInfo.Plane = aPlane; + aClippingPlaneInfo.ActorList = anActorList; + aClippingPlaneInfoList.push_back( aClippingPlaneInfo ); + } + break; + } + } + } + } + // update all VTK views QList lst; getApp()->viewManagers(lst); @@ -4863,7 +5431,7 @@ void SMESHGUI::restoreVisualParameters (int savePoint) int SMESHGUI::addVtkFontPref( const QString& label, const int pId, const QString& param ) { int tfont = addPreference( label, pId, LightApp_Preferences::Font, "VISU", param ); - + setPreferenceProperty( tfont, "mode", QtxFontEdit::Custom ); QStringList fam; diff --git a/src/SMESHGUI/SMESHGUI.h b/src/SMESHGUI/SMESHGUI.h index 0099a20bd..7aa14367f 100644 --- a/src/SMESHGUI/SMESHGUI.h +++ b/src/SMESHGUI/SMESHGUI.h @@ -39,6 +39,14 @@ #include #include CORBA_SERVER_HEADER(SMESH_Gen) +// VTK includes +#include +#include + +class vtkActor; +class vtkCallbackCommand; +class vtkObject; + class QDialog; class SUIT_Desktop; @@ -52,10 +60,24 @@ class SalomeApp_Study; class LightApp_Selection; class LightApp_SelectionMgr; +class SMESH_Actor; class SMESHGUI_FilterLibraryDlg; typedef std::map SMESHGUI_StudyId2MarkerMap; +namespace SMESH +{ + class OrientedPlane; + struct ClippingPlaneInfo + { + OrientedPlane* Plane; + std::list ActorList; + }; +} + +typedef std::list SMESHGUI_ClippingPlaneInfoList; +typedef std::map SMESHGUI_ClippingPlaneInfoMap; + //================================================================================= // class : SMESHGUI // purpose : @@ -77,7 +99,7 @@ public : bool isActiveStudyLocked(); - static bool automaticUpdate(); + static bool automaticUpdate(unsigned int requestedSize = 0, bool* limitExceeded = 0); static void Modified( bool = true ); @@ -122,6 +144,10 @@ public : virtual void storeVisualParameters (int savePoint); virtual void restoreVisualParameters(int savePoint); + virtual void addActorAsObserver( SMESH_Actor* theActor ); + + SMESHGUI_ClippingPlaneInfoMap& getClippingPlaneInfoMap() { return myClippingPlaneInfoMap; } + public slots: virtual bool deactivateModule( SUIT_Study* ); virtual bool activateModule( SUIT_Study* ); @@ -130,6 +156,7 @@ public slots: private slots: void OnGUIEvent(); void onViewManagerActivated( SUIT_ViewManager* ); + void onViewManagerRemoved( SUIT_ViewManager* ); void onOperationCommited( SUIT_Operation* ); void onOperationAborted( SUIT_Operation* ); void onHypothesisEdit( int result ); @@ -145,7 +172,8 @@ protected: const QString&, const QString& = QString(), const int = 0, - const bool = false ); + const bool = false, + const QString& = QString() ); void createPopupItem( const int, const QString&, const QString&, @@ -158,6 +186,11 @@ protected: virtual bool reusableOperation( const int id ); + static void ProcessEvents( vtkObject* theObject, + unsigned long theEvent, + void* theClientData, + void* theCallData ); + private: void OnEditDelete(); int addVtkFontPref( const QString& label, @@ -174,6 +207,10 @@ private : SMESHGUI_FilterLibraryDlg* myFilterLibraryDlg; SMESHGUI_StudyId2MarkerMap myMarkerMap; + SMESHGUI_ClippingPlaneInfoMap myClippingPlaneInfoMap; + + vtkSmartPointer myEventCallbackCommand; + vtkFloatingPointType myPriority; }; #endif // SMESHGUI_H diff --git a/src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx b/src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx index a5d12e559..b2cd9e46d 100644 --- a/src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx @@ -492,19 +492,19 @@ void SMESHGUI_AddMeshElementDlg::ClickOnApply() if( addToGroup ) { aGroupName = ComboBox_GroupName->currentText(); for ( int i = 1; i < ComboBox_GroupName->count(); i++ ) { - QString aName = ComboBox_GroupName->itemText( i ); - if ( aGroupName == aName && ( i == ComboBox_GroupName->currentIndex() || idx == 0 ) ) - idx = i; + QString aName = ComboBox_GroupName->itemText( i ); + if ( aGroupName == aName && ( i == ComboBox_GroupName->currentIndex() || idx == 0 ) ) + idx = i; } if ( idx > 0 ) { - SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( myGroups[idx-1] ); - if ( !aGeomGroup->_is_nil() ) { - int res = SUIT_MessageBox::question( this, tr( "SMESH_WRN_WARNING" ), - tr( "MESH_STANDALONE_GRP_CHOSEN" ).arg( aGroupName ), - tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ); - if ( res == 1 ) return; - } - aGroup = myGroups[idx-1]; + SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( myGroups[idx-1] ); + if ( !aGeomGroup->_is_nil() ) { + int res = SUIT_MessageBox::question( this, tr( "SMESH_WRN_WARNING" ), + tr( "MESH_STANDALONE_GRP_CHOSEN" ).arg( aGroupName ), + tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ); + if ( res == 1 ) return; + } + aGroup = myGroups[idx-1]; } } @@ -530,24 +530,24 @@ void SMESHGUI_AddMeshElementDlg::ClickOnApply() if ( anElemId != -1 && addToGroup && !aGroupName.isEmpty() ) { SMESH::SMESH_Group_var aGroupUsed; if ( aGroup->_is_nil() ) { - // create new group - aGroupUsed = SMESH::AddGroup( myMesh, (SMESH::ElementType)myElementType, aGroupName ); - if ( !aGroupUsed->_is_nil() ) { - myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroupUsed)); - ComboBox_GroupName->addItem( aGroupName ); - } + // create new group + aGroupUsed = SMESH::AddGroup( myMesh, (SMESH::ElementType)myElementType, aGroupName ); + if ( !aGroupUsed->_is_nil() ) { + myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroupUsed)); + ComboBox_GroupName->addItem( aGroupName ); + } } else { - SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGroup ); - if ( !aGeomGroup->_is_nil() ) { - aGroupUsed = myMesh->ConvertToStandalone( aGeomGroup ); - if ( !aGroupUsed->_is_nil() && idx > 0 ) { - myGroups[idx-1] = SMESH::SMESH_GroupBase::_duplicate(aGroupUsed); - SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); - } - } - else - aGroupUsed = SMESH::SMESH_Group::_narrow( aGroup ); + SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGroup ); + if ( !aGeomGroup->_is_nil() ) { + aGroupUsed = myMesh->ConvertToStandalone( aGeomGroup ); + if ( !aGroupUsed->_is_nil() && idx > 0 ) { + myGroups[idx-1] = SMESH::SMESH_GroupBase::_duplicate(aGroupUsed); + SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); + } + } + else + aGroupUsed = SMESH::SMESH_Group::_narrow( aGroup ); } if ( !aGroupUsed->_is_nil() ) { @@ -736,11 +736,11 @@ void SMESHGUI_AddMeshElementDlg::SelectionIntoArgument() for ( int i = 0, n = aListOfGroups.length(); i < n; i++ ) { SMESH::SMESH_GroupBase_var aGroup = aListOfGroups[i]; if ( !aGroup->_is_nil() && aGroup->GetType() == (SMESH::ElementType)myElementType ) { - QString aGroupName( aGroup->GetName() ); - if ( !aGroupName.isEmpty() ) { - myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroup)); - ComboBox_GroupName->addItem( aGroupName ); - } + QString aGroupName( aGroup->GetName() ); + if ( !aGroupName.isEmpty() ) { + myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroup)); + ComboBox_GroupName->addItem( aGroupName ); + } } } } diff --git a/src/SMESHGUI/SMESHGUI_AddQuadraticElementDlg.cxx b/src/SMESHGUI/SMESHGUI_AddQuadraticElementDlg.cxx index d190c35e3..f75dd31d8 100644 --- a/src/SMESHGUI/SMESHGUI_AddQuadraticElementDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_AddQuadraticElementDlg.cxx @@ -731,15 +731,15 @@ void SMESHGUI_AddQuadraticElementDlg::ClickOnApply() for ( int i = 1; i < ComboBox_GroupName->count(); i++ ) { QString aName = ComboBox_GroupName->itemText( i ); if ( aGroupName == aName && ( i == ComboBox_GroupName->currentIndex() || idx == 0 ) ) - idx = i; + idx = i; } if ( idx > 0 ) { SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( myGroups[idx-1] ); if ( !aGeomGroup->_is_nil() ) { - int res = SUIT_MessageBox::question( this, tr( "SMESH_WRN_WARNING" ), - tr( "MESH_STANDALONE_GRP_CHOSEN" ).arg( aGroupName ), - tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ); - if ( res == 1 ) return; + int res = SUIT_MessageBox::question( this, tr( "SMESH_WRN_WARNING" ), + tr( "MESH_STANDALONE_GRP_CHOSEN" ).arg( aGroupName ), + tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ); + if ( res == 1 ) return; } aGroup = myGroups[idx-1]; } @@ -771,21 +771,21 @@ void SMESHGUI_AddQuadraticElementDlg::ClickOnApply() // create new group aGroupUsed = SMESH::AddGroup( myMesh, anElementType, aGroupName ); if ( !aGroupUsed->_is_nil() ) { - myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroupUsed)); - ComboBox_GroupName->addItem( aGroupName ); + myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroupUsed)); + ComboBox_GroupName->addItem( aGroupName ); } } else { SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGroup ); if ( !aGeomGroup->_is_nil() ) { - aGroupUsed = myMesh->ConvertToStandalone( aGeomGroup ); - if ( !aGroupUsed->_is_nil() && idx > 0 ) { - myGroups[idx-1] = SMESH::SMESH_GroupBase::_duplicate(aGroupUsed); - SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); - } + aGroupUsed = myMesh->ConvertToStandalone( aGeomGroup ); + if ( !aGroupUsed->_is_nil() && idx > 0 ) { + myGroups[idx-1] = SMESH::SMESH_GroupBase::_duplicate(aGroupUsed); + SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); + } } else - aGroupUsed = SMESH::SMESH_Group::_narrow( aGroup ); + aGroupUsed = SMESH::SMESH_Group::_narrow( aGroup ); } if ( !aGroupUsed->_is_nil() ) { @@ -974,11 +974,11 @@ void SMESHGUI_AddQuadraticElementDlg::SelectionIntoArgument() for ( int i = 0, n = aListOfGroups.length(); i < n; i++ ) { SMESH::SMESH_GroupBase_var aGroup = aListOfGroups[i]; if ( !aGroup->_is_nil() && aGroup->GetType() == anElementType ) { - QString aGroupName( aGroup->GetName() ); - if ( !aGroupName.isEmpty() ) { - myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroup)); - ComboBox_GroupName->addItem( aGroupName ); - } + QString aGroupName( aGroup->GetName() ); + if ( !aGroupName.isEmpty() ) { + myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroup)); + ComboBox_GroupName->addItem( aGroupName ); + } } } } diff --git a/src/SMESHGUI/SMESHGUI_BuildCompoundDlg.cxx b/src/SMESHGUI/SMESHGUI_BuildCompoundDlg.cxx index bc6c1daf5..4fceb54be 100644 --- a/src/SMESHGUI/SMESHGUI_BuildCompoundDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_BuildCompoundDlg.cxx @@ -19,12 +19,11 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_BuildCompoundDlg.cxx +// Author : Alexander KOVALEV, Open CASCADE S.A.S. +// SMESH includes -// SMESH SMESHGUI : GUI for SMESH component -// File : SMESHGUI_BuildCompoundDlg.cxx -// Author : Alexander KOVALEV, Open CASCADE S.A.S. -// SMESH includes -// #include "SMESHGUI_BuildCompoundDlg.h" #include "SMESHGUI.h" @@ -67,6 +66,10 @@ #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 + //================================================================================= // name : SMESHGUI_BuildCompoundDlg // Purpose : @@ -143,7 +146,7 @@ SMESHGUI_BuildCompoundDlg::SMESHGUI_BuildCompoundDlg( SMESHGUI* theModule ) GroupArgsLayout->addWidget(TextLabelMeshes, 0, 0); GroupArgsLayout->addWidget(SelectButton, 0, 1); GroupArgsLayout->addWidget(LineEditMeshes, 0, 2, 1, 2); - GroupArgsLayout->addWidget(TextLabelUnion, 1, 0, 1, 3); + GroupArgsLayout->addWidget(TextLabelUnion, 1, 0, 1, 3); GroupArgsLayout->addWidget(ComboBoxUnion, 1, 3); GroupArgsLayout->addWidget(CheckBoxCommon, 2, 0, 1, 4); GroupArgsLayout->addWidget(CheckBoxMerge, 3, 0, 1, 4); @@ -301,16 +304,16 @@ bool SMESHGUI_BuildCompoundDlg::ClickOnApply() SMESH::SMESH_Gen_var aSMESHGen = SMESHGUI::GetSMESHGen(); // concatenate meshes if(CheckBoxCommon->isChecked()) - aCompoundMesh = aSMESHGen->ConcatenateWithGroups(myMeshArray, - !(ComboBoxUnion->currentIndex()), - CheckBoxMerge->isChecked(), + aCompoundMesh = aSMESHGen->ConcatenateWithGroups(myMeshArray, + !(ComboBoxUnion->currentIndex()), + CheckBoxMerge->isChecked(), SpinBoxTol->GetValue()); else - aCompoundMesh = aSMESHGen->Concatenate(myMeshArray, - !(ComboBoxUnion->currentIndex()), - CheckBoxMerge->isChecked(), + aCompoundMesh = aSMESHGen->Concatenate(myMeshArray, + !(ComboBoxUnion->currentIndex()), + CheckBoxMerge->isChecked(), SpinBoxTol->GetValue()); - + aCompoundMesh->SetParameters( aParameters.join(":").toLatin1().constData() ); SMESH::SetName( SMESH::FindSObject( aCompoundMesh ), LineEditName->text() ); @@ -325,7 +328,7 @@ bool SMESHGUI_BuildCompoundDlg::ClickOnApply() if ( SMESHGUI::automaticUpdate() ) { mySelectionMgr->clearSelected(); SMESH::UpdateView(); - + _PTR(SObject) aSO = SMESH::FindSObject(aCompoundMesh.in()); if ( SMESH_Actor* anActor = SMESH::CreateActor(aSO->GetStudy(), aSO->GetID().c_str()) ) SMESH::DisplayActor(SMESH::GetActiveWindow(), anActor); @@ -333,6 +336,14 @@ 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->Destroy(); +#endif + return true; } return false; @@ -368,7 +379,7 @@ void SMESHGUI_BuildCompoundDlg::ClickOnCancel() void SMESHGUI_BuildCompoundDlg::ClickOnHelp() { LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication()); - if (app) + if (app) app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName); else { SUIT_MessageBox::warning(this, tr("WRN_WARNING"), @@ -503,7 +514,6 @@ void SMESHGUI_BuildCompoundDlg::keyPressEvent( QKeyEvent* e ) //================================================================================= void SMESHGUI_BuildCompoundDlg::onSelectMerge(bool toMerge) { - TextLabelTol->setEnabled(toMerge); SpinBoxTol->setEnabled(toMerge); if(!toMerge) diff --git a/src/SMESHGUI/SMESHGUI_ClippingDlg.cxx b/src/SMESHGUI/SMESHGUI_ClippingDlg.cxx index 13bdc8eb4..ac190be77 100644 --- a/src/SMESHGUI/SMESHGUI_ClippingDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ClippingDlg.cxx @@ -41,11 +41,15 @@ #include #include #include +#include #include +#include + #include -#include + +#include #include @@ -59,139 +63,138 @@ #include #include #include +#include // VTK includes #include -#include #include #include #include #include +#include #define SPACING 6 #define MARGIN 11 -class OrientedPlane: public vtkPlane +//================================================================================= +// class : OrientedPlane +// purpose : +//================================================================================= +SMESH::OrientedPlane* SMESH::OrientedPlane::New() { - QPointer myViewWindow; - - vtkDataSetMapper* myMapper; - -public: - static OrientedPlane *New() - { - return new OrientedPlane(); - } - static OrientedPlane *New(SVTK_ViewWindow* theViewWindow) - { - return new OrientedPlane(theViewWindow); - } - vtkTypeMacro (OrientedPlane, vtkPlane); - - SMESH::Orientation myOrientation; - float myDistance; - double myAngle[2]; + return new OrientedPlane(); +} - vtkPlaneSource* myPlaneSource; - SALOME_Actor *myActor; +SMESH::OrientedPlane* SMESH::OrientedPlane::New(SVTK_ViewWindow* theViewWindow) +{ + return new OrientedPlane(theViewWindow); +} - void SetOrientation (SMESH::Orientation theOrientation) { myOrientation = theOrientation; } - SMESH::Orientation GetOrientation() { return myOrientation; } +void SMESH::OrientedPlane::ShallowCopy(SMESH::OrientedPlane* theOrientedPlane) +{ + SetNormal(theOrientedPlane->GetNormal()); + SetOrigin(theOrientedPlane->GetOrigin()); - void SetDistance (float theDistance) { myDistance = theDistance; } - float GetDistance() { return myDistance; } + myOrientation = theOrientedPlane->GetOrientation(); + myDistance = theOrientedPlane->GetDistance(); - void ShallowCopy (OrientedPlane* theOrientedPlane) - { - SetNormal(theOrientedPlane->GetNormal()); - SetOrigin(theOrientedPlane->GetOrigin()); + myAngle[0] = theOrientedPlane->myAngle[0]; + myAngle[1] = theOrientedPlane->myAngle[1]; - myOrientation = theOrientedPlane->GetOrientation(); - myDistance = theOrientedPlane->GetDistance(); + myPlaneSource->SetNormal(theOrientedPlane->myPlaneSource->GetNormal()); + myPlaneSource->SetOrigin(theOrientedPlane->myPlaneSource->GetOrigin()); + myPlaneSource->SetPoint1(theOrientedPlane->myPlaneSource->GetPoint1()); + myPlaneSource->SetPoint2(theOrientedPlane->myPlaneSource->GetPoint2()); +} - myAngle[0] = theOrientedPlane->myAngle[0]; - myAngle[1] = theOrientedPlane->myAngle[1]; +SMESH::OrientedPlane::OrientedPlane(SVTK_ViewWindow* theViewWindow): + myViewWindow(theViewWindow), + myOrientation(SMESH::XY), + myDistance(0.5) +{ + Init(); + myViewWindow->AddActor(myActor); +} - myPlaneSource->SetNormal(theOrientedPlane->myPlaneSource->GetNormal()); - myPlaneSource->SetOrigin(theOrientedPlane->myPlaneSource->GetOrigin()); - myPlaneSource->SetPoint1(theOrientedPlane->myPlaneSource->GetPoint1()); - myPlaneSource->SetPoint2(theOrientedPlane->myPlaneSource->GetPoint2()); - } +SMESH::OrientedPlane::OrientedPlane(): + myOrientation(SMESH::XY), + myViewWindow(NULL), + myDistance(0.5) +{ + Init(); +} -protected: - OrientedPlane(SVTK_ViewWindow* theViewWindow): - myViewWindow(theViewWindow), - myOrientation(SMESH::XY), - myDistance(0.5) - { - Init(); - myViewWindow->AddActor(myActor); - } +void SMESH::OrientedPlane::Init() +{ + myPlaneSource = vtkPlaneSource::New(); + + myAngle[0] = myAngle[1] = 0.0; + + // Create and display actor + myMapper = vtkDataSetMapper::New(); + myMapper->SetInput(myPlaneSource->GetOutput()); + + myActor = SALOME_Actor::New(); + myActor->VisibilityOff(); + myActor->PickableOff(); + myActor->SetInfinitive(true); + myActor->SetMapper(myMapper); + + vtkFloatingPointType anRGB[3]; + vtkProperty* aProp = vtkProperty::New(); + SMESH::GetColor( "SMESH", "fill_color", anRGB[0], anRGB[1], anRGB[2], QColor( 0, 170, 255 ) ); + aProp->SetColor(anRGB[0],anRGB[1],anRGB[2]); + aProp->SetOpacity(0.75); + myActor->SetProperty(aProp); + aProp->Delete(); + + vtkProperty* aBackProp = vtkProperty::New(); + SMESH::GetColor( "SMESH", "backface_color", anRGB[0], anRGB[1], anRGB[2], QColor( 0, 0, 255 ) ); + aBackProp->SetColor(anRGB[0],anRGB[1],anRGB[2]); + aBackProp->SetOpacity(0.75); + myActor->SetBackfaceProperty(aBackProp); + aBackProp->Delete(); +} - OrientedPlane(): - myOrientation(SMESH::XY), - myViewWindow(NULL), - myDistance(0.5) - { - Init(); - } +SMESH::OrientedPlane::~OrientedPlane() +{ + if (myViewWindow) + myViewWindow->RemoveActor(myActor); + myActor->Delete(); + + myMapper->RemoveAllInputs(); + myMapper->Delete(); - void Init() - { - myPlaneSource = vtkPlaneSource::New(); - - myAngle[0] = myAngle[1] = 0.0; - - // Create and display actor - myMapper = vtkDataSetMapper::New(); - myMapper->SetInput(myPlaneSource->GetOutput()); - - myActor = SALOME_Actor::New(); - myActor->VisibilityOff(); - myActor->PickableOff(); - myActor->SetInfinitive(true); - myActor->SetMapper(myMapper); - - vtkFloatingPointType anRGB[3]; - vtkProperty* aProp = vtkProperty::New(); - SMESH::GetColor( "SMESH", "fill_color", anRGB[0], anRGB[1], anRGB[2], QColor( 0, 170, 255 ) ); - aProp->SetColor(anRGB[0],anRGB[1],anRGB[2]); - aProp->SetOpacity(0.75); - myActor->SetProperty(aProp); - aProp->Delete(); - - vtkProperty* aBackProp = vtkProperty::New(); - SMESH::GetColor( "SMESH", "backface_color", anRGB[0], anRGB[1], anRGB[2], QColor( 0, 0, 255 ) ); - aBackProp->SetColor(anRGB[0],anRGB[1],anRGB[2]); - aBackProp->SetOpacity(0.75); - myActor->SetBackfaceProperty(aBackProp); - aBackProp->Delete(); - } + // commented: porting to vtk 5.0 + // myPlaneSource->UnRegisterAllOutputs(); + myPlaneSource->Delete(); +} - ~OrientedPlane(){ - if (myViewWindow) - myViewWindow->RemoveActor(myActor); - myActor->Delete(); - - myMapper->RemoveAllInputs(); - myMapper->Delete(); +//================================================================================= +// class : ActorItem +// purpose : +//================================================================================= +class ActorItem : public QListWidgetItem +{ +public: + ActorItem( SMESH_Actor* theActor, const QString& theName, QListWidget* theListWidget ) : + QListWidgetItem( theName, theListWidget ), + myActor( theActor ) {} - // commented: porting to vtk 5.0 - // myPlaneSource->UnRegisterAllOutputs(); - myPlaneSource->Delete(); - }; + SMESH_Actor* getActor() const { return myActor; } private: - // Not implemented. - OrientedPlane (const OrientedPlane&); - void operator= (const OrientedPlane&); - + SMESH_Actor* myActor; }; -struct TSetVisiblity { - TSetVisiblity(int theIsVisible): myIsVisible(theIsVisible){} - void operator()(SMESH::TVTKPlane& theOrientedPlane){ - theOrientedPlane->myActor->SetVisibility(myIsVisible); +//================================================================================= +// class : TSetVisibility +// purpose : +//================================================================================= +struct TSetVisibility { + TSetVisibility(int theIsVisible): myIsVisible(theIsVisible){} + void operator()(SMESH::TPlaneData& thePlaneData){ + thePlaneData.Plane.GetPointer()->myActor->SetVisibility(myIsVisible); } int myIsVisible; }; @@ -200,13 +203,13 @@ struct TSetVisiblity { // used in SMESHGUI::restoreVisualParameters() to avoid // declaration of OrientedPlane outside of SMESHGUI_ClippingDlg.cxx //================================================================================= -void SMESHGUI_ClippingDlg::AddPlane (SMESH_Actor* theActor, - SVTK_ViewWindow* theViewWindow, - SMESH::Orientation theOrientation, - double theDistance, - vtkFloatingPointType theAngle[2]) +SMESH::OrientedPlane* SMESHGUI_ClippingDlg::AddPlane (SMESH::TActorList theActorList, + SVTK_ViewWindow* theViewWindow, + SMESH::Orientation theOrientation, + double theDistance, + const vtkFloatingPointType theAngle[2]) { - OrientedPlane* aPlane = OrientedPlane::New(theViewWindow); + SMESH::OrientedPlane* aPlane = SMESH::OrientedPlane::New(theViewWindow); aPlane->myAngle[0] = theAngle[0]; aPlane->myAngle[1] = theAngle[1]; @@ -256,14 +259,26 @@ void SMESHGUI_ClippingDlg::AddPlane (SMESH_Actor* theActor, vtkMath::Cross(aNormal,aDir[1],aDir[0]); } - // ??? - theActor->SetPlaneParam(aNormal, theDistance, aPlane); + vtkFloatingPointType aBounds[6]; + vtkFloatingPointType anOrigin[3]; + bool anIsOk = SMESH::ComputeClippingPlaneParameters( theActorList, + aNormal, + theDistance, + aBounds, + anOrigin ); + if( !anIsOk ) + return NULL; - vtkDataSet* aDataSet = theActor->GetInput(); - vtkFloatingPointType *aPnt = aDataSet->GetCenter(); + aPlane->SetNormal( aNormal ); + aPlane->SetOrigin( anOrigin ); - vtkFloatingPointType* anOrigin = aPlane->GetOrigin(); - vtkFloatingPointType aDel = aDataSet->GetLength()/2.0; + vtkFloatingPointType aPnt[3] = { ( aBounds[0] + aBounds[1] ) / 2., + ( aBounds[2] + aBounds[3] ) / 2., + ( aBounds[4] + aBounds[5] ) / 2. }; + + vtkFloatingPointType aDel = pow( pow( aBounds[1] - aBounds[0], 2 ) + + pow( aBounds[3] - aBounds[2], 2 ) + + pow( aBounds[5] - aBounds[4], 2 ), 0.5 ); vtkFloatingPointType aDelta[2][3] = {{aDir[0][0]*aDel, aDir[0][1]*aDel, aDir[0][2]*aDel}, {aDir[1][0]*aDel, aDir[1][1]*aDel, aDir[1][2]*aDel}}; @@ -299,28 +314,13 @@ void SMESHGUI_ClippingDlg::AddPlane (SMESH_Actor* theActor, aPlaneSource->SetPoint1(aPnt1[0],aPnt1[1],aPnt1[2]); aPlaneSource->SetPoint2(aPnt2[0],aPnt2[1],aPnt2[2]); - theActor->AddClippingPlane(aPlane); - aPlane->Delete(); -} + SMESH::TActorList::iterator anIter = theActorList.begin(); + for ( ; anIter != theActorList.end(); anIter++ ) + if( vtkActor* aVTKActor = *anIter ) + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) + anActor->AddClippingPlane( aPlane ); -//================================================================================= -// used in SMESHGUI::restoreVisualParameters() to avoid -// declaration of OrientedPlane outside of SMESHGUI_ClippingDlg.cxx -//================================================================================= -void SMESHGUI_ClippingDlg::GetPlaneParam (SMESH_Actor* theActor, - int thePlaneIndex, - SMESH::Orientation& theOrientation, - double& theDistance, - vtkFloatingPointType* theAngle) -{ - if (vtkPlane* aPln = theActor->GetClippingPlane(thePlaneIndex)) { - if (OrientedPlane* aPlane = OrientedPlane::SafeDownCast(aPln)) { - theOrientation = aPlane->GetOrientation(); - theDistance = aPlane->GetDistance(); - theAngle[0] = aPlane->myAngle[0]; - theAngle[1] = aPlane->myAngle[1]; - } - } + return aPlane; } //================================================================================= @@ -328,11 +328,10 @@ void SMESHGUI_ClippingDlg::GetPlaneParam (SMESH_Actor* theActor, // purpose : // //================================================================================= -SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): +SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule, SVTK_ViewWindow* theViewWindow ): QDialog( SMESH::GetDesktop(theModule) ), - mySelector(SMESH::GetViewWindow(theModule)->GetSelector()), - mySelectionMgr(SMESH::GetSelectionMgr(theModule)), - mySMESHGUI(theModule) + mySMESHGUI(theModule), + myViewWindow(theViewWindow) { setModal( false ); setAttribute( Qt::WA_DeleteOnClose, true ); @@ -345,7 +344,7 @@ SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): // Controls for selecting, creating, deleting planes QGroupBox* GroupPlanes = new QGroupBox(tr("CLIP_PLANES"), this); - QHBoxLayout* GroupPlanesLayout = new QHBoxLayout(GroupPlanes); + QGridLayout* GroupPlanesLayout = new QGridLayout(GroupPlanes); GroupPlanesLayout->setSpacing(SPACING); GroupPlanesLayout->setMargin(MARGIN); @@ -355,10 +354,21 @@ SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): buttonDelete = new QPushButton(tr("SMESH_BUT_DELETE"), GroupPlanes); - GroupPlanesLayout->addWidget(ComboBoxPlanes); - GroupPlanesLayout->addStretch(); - GroupPlanesLayout->addWidget(buttonNew); - GroupPlanesLayout->addWidget(buttonDelete); + QLabel* aLabel = new QLabel(tr("MESHES_SUBMESHES_GROUPS"), GroupPlanes); + + ActorList = new QListWidget(GroupPlanes); + ActorList->setSelectionMode(QAbstractItemView::SingleSelection); + + SelectAllCheckBox = new QCheckBox(tr("SELECT_ALL"), GroupPlanes); + + GroupPlanesLayout->addWidget(ComboBoxPlanes, 0, 0); + GroupPlanesLayout->addWidget(new QWidget(), 0, 1); + GroupPlanesLayout->addWidget(buttonNew, 0, 2); + GroupPlanesLayout->addWidget(buttonDelete, 0, 3); + GroupPlanesLayout->addWidget(aLabel, 1, 0, 1, 4); + GroupPlanesLayout->addWidget(ActorList, 2, 0, 1, 4); + GroupPlanesLayout->addWidget(SelectAllCheckBox, 3, 0, 1, 4); + GroupPlanesLayout->setColumnStretch( 1, 1 ); // Controls for defining plane parameters QGroupBox* GroupParameters = new QGroupBox(tr("SMESH_PARAMETERS"), this); @@ -437,9 +447,10 @@ SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): SpinBoxDistance->SetValue(0.5); - myActor = 0; myIsSelectPlane = false; - onSelectionChanged(); + + initializePlaneData(); + synchronize(); myHelpFileName = "clipping_page.html"; @@ -447,6 +458,8 @@ SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): connect(ComboBoxPlanes, SIGNAL(activated(int)), this, SLOT(onSelectPlane(int))); connect(buttonNew, SIGNAL(clicked()), this, SLOT(ClickOnNew())); connect(buttonDelete, SIGNAL(clicked()), this, SLOT(ClickOnDelete())); + connect(ActorList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(onActorItemChanged(QListWidgetItem*))); + connect(SelectAllCheckBox, SIGNAL(stateChanged(int)), this, SLOT(onSelectAll(int))); connect(ComboBoxOrientation, SIGNAL(activated(int)), this, SLOT(onSelectOrientation(int))); connect(SpinBoxDistance, SIGNAL(valueChanged(double)), this, SLOT(SetCurrentPlaneParam())); connect(SpinBoxRot1, SIGNAL(valueChanged(double)), this, SLOT(SetCurrentPlaneParam())); @@ -458,7 +471,6 @@ SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): connect(buttonApply, SIGNAL(clicked()), this, SLOT(ClickOnApply())); connect(buttonHelp, SIGNAL(clicked()), this, SLOT(ClickOnHelp())); connect(mySMESHGUI, SIGNAL (SignalCloseAllDialogs()), this, SLOT(ClickOnCancel())); - connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(onSelectionChanged())); /* to close dialog if study frame change */ connect(mySMESHGUI, SIGNAL (SignalStudyFrameChanged()), this, SLOT(ClickOnCancel())); @@ -472,10 +484,9 @@ SMESHGUI_ClippingDlg::SMESHGUI_ClippingDlg( SMESHGUI* theModule ): SMESHGUI_ClippingDlg::~SMESHGUI_ClippingDlg() { // no need to delete child widgets, Qt does it all for us - std::for_each(myPlanes.begin(),myPlanes.end(),TSetVisiblity(false)); - if (mySMESHGUI) - if (SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(mySMESHGUI)) - SMESH::RenderViewWindow(aViewWindow); + std::for_each(myPlanes.begin(),myPlanes.end(),TSetVisibility(false)); + if (myViewWindow) + SMESH::RenderViewWindow(myViewWindow); } double SMESHGUI_ClippingDlg::getDistance() const @@ -504,27 +515,56 @@ double SMESHGUI_ClippingDlg::getRotation2() const //======================================================================= void SMESHGUI_ClippingDlg::ClickOnApply() { - if (!myActor) - return; - - if (SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(mySMESHGUI)) { + if (myViewWindow) { SUIT_OverrideCursor wc; QWidget *aCurrWid = this->focusWidget(); aCurrWid->clearFocus(); aCurrWid->setFocus(); - myActor->RemoveAllClippingPlanes(); - - SMESH::TPlanes::iterator anIter = myPlanes.begin(); - for ( ; anIter != myPlanes.end(); anIter++) { - OrientedPlane* anOrientedPlane = OrientedPlane::New(aViewWindow); - anOrientedPlane->ShallowCopy(anIter->GetPointer()); - myActor->AddClippingPlane(anOrientedPlane); - anOrientedPlane->Delete(); + SMESHGUI_ClippingPlaneInfoMap& aClippingPlaneInfoMap = mySMESHGUI->getClippingPlaneInfoMap(); + SMESHGUI_ClippingPlaneInfoList& aClippingPlaneInfoList = aClippingPlaneInfoMap[ myViewWindow->getViewManager() ]; + + // clean memory allocated for planes + SMESHGUI_ClippingPlaneInfoList::iterator anIter1 = aClippingPlaneInfoList.begin(); + for( ; anIter1 != aClippingPlaneInfoList.end(); anIter1++ ) + if( SMESH::OrientedPlane* aPlane = (*anIter1).Plane ) + aPlane->Delete(); + + aClippingPlaneInfoList.clear(); + + VTK::ActorCollectionCopy aCopy( myViewWindow->getRenderer()->GetActors() ); + vtkActorCollection* anAllActors = aCopy.GetActors(); + anAllActors->InitTraversal(); + while( vtkActor* aVTKActor = anAllActors->GetNextActor() ) + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) + anActor->RemoveAllClippingPlanes(); + + SMESH::TPlaneDataVector::iterator anIter2 = myPlanes.begin(); + for( ; anIter2 != myPlanes.end(); anIter2++ ) { + SMESH::TPlaneData aPlaneData = *anIter2; + SMESH::TPlane aPlane = aPlaneData.Plane; + SMESH::TActorList anActorList = aPlaneData.ActorList; + if( anActorList.empty() ) + continue; + + SMESH::OrientedPlane* anOrientedPlane = SMESH::OrientedPlane::New(myViewWindow); + anOrientedPlane->ShallowCopy(aPlane.GetPointer()); + + SMESH::TActorList::iterator anIter3 = anActorList.begin(); + for( ; anIter3 != anActorList.end(); anIter3++ ) + if( vtkActor* aVTKActor = *anIter3 ) + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) + anActor->AddClippingPlane(anOrientedPlane); + + SMESH::ClippingPlaneInfo aClippingPlaneInfo; + aClippingPlaneInfo.Plane = anOrientedPlane; + aClippingPlaneInfo.ActorList = anActorList; + + aClippingPlaneInfoList.push_back( aClippingPlaneInfo ); } - SMESH::RenderViewWindow(aViewWindow); + SMESH::RenderViewWindow( myViewWindow ); } } @@ -571,53 +611,17 @@ void SMESHGUI_ClippingDlg::ClickOnHelp() } } -//================================================================================= -// function : onSelectionChanged() -// purpose : Called when selection is changed -//================================================================================= -void SMESHGUI_ClippingDlg::onSelectionChanged() -{ - if (SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(mySMESHGUI)) { - const SALOME_ListIO& aList = mySelector->StoredIObjects(); - if (aList.Extent() > 0) { - Handle(SALOME_InteractiveObject) IOS = aList.First(); - myActor = SMESH::FindActorByEntry(IOS->getEntry()); - if (myActor) { - std::for_each(myPlanes.begin(),myPlanes.end(),TSetVisiblity(false)); - myPlanes.clear(); - - vtkIdType anId = 0, anEnd = myActor->GetNumberOfClippingPlanes(); - for ( ; anId < anEnd; anId++) { - if (vtkImplicitFunction* aFunction = myActor->GetClippingPlane(anId)) { - if(OrientedPlane* aPlane = OrientedPlane::SafeDownCast(aFunction)){ - OrientedPlane* anOrientedPlane = OrientedPlane::New(aViewWindow); - SMESH::TVTKPlane aTVTKPlane(anOrientedPlane); - anOrientedPlane->Delete(); - aTVTKPlane->ShallowCopy(aPlane); - myPlanes.push_back(aTVTKPlane); - } - } - } - - std::for_each(myPlanes.begin(),myPlanes.end(), - TSetVisiblity(PreviewCheckBox->isChecked())); - } - } - SMESH::RenderViewWindow(aViewWindow); - } - Sinchronize(); -} - //======================================================================= // function : onSelectPlane() // purpose : //======================================================================= void SMESHGUI_ClippingDlg::onSelectPlane (int theIndex) { - if (!myActor || myPlanes.empty()) + if (myPlanes.empty()) return; - OrientedPlane* aPlane = myPlanes[theIndex].GetPointer(); + SMESH::TPlaneData aPlaneData = myPlanes[theIndex]; + SMESH::OrientedPlane* aPlane = aPlaneData.Plane.GetPointer(); // Orientation SMESH::Orientation anOrientation = aPlane->GetOrientation(); @@ -644,6 +648,11 @@ void SMESHGUI_ClippingDlg::onSelectPlane (int theIndex) break; } myIsSelectPlane = false; + + // Actors + bool anIsBlocked = ActorList->blockSignals( true ); + updateActorList(); + ActorList->blockSignals( anIsBlocked ); } //======================================================================= @@ -652,19 +661,31 @@ void SMESHGUI_ClippingDlg::onSelectPlane (int theIndex) //======================================================================= void SMESHGUI_ClippingDlg::ClickOnNew() { - if (!myActor) - return; + if(myViewWindow){ + SMESH::OrientedPlane* aPlane = SMESH::OrientedPlane::New(myViewWindow); + SMESH::TPlane aTPlane(aPlane); + + SMESH::TActorList anActorList; + VTK::ActorCollectionCopy aCopy( myViewWindow->getRenderer()->GetActors() ); + vtkActorCollection* anAllActors = aCopy.GetActors(); + anAllActors->InitTraversal(); + while( vtkActor* aVTKActor = anAllActors->GetNextActor() ) + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) + anActorList.push_back( anActor ); - if(SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(mySMESHGUI)){ - OrientedPlane* aPlane = OrientedPlane::New(aViewWindow); - SMESH::TVTKPlane aTVTKPlane(aPlane); - myPlanes.push_back(aTVTKPlane); + SMESH::TPlaneData aPlaneData(aTPlane, anActorList); + + myPlanes.push_back(aPlaneData); if (PreviewCheckBox->isChecked()) - aTVTKPlane->myActor->VisibilityOn(); - - Sinchronize(); + aTPlane->myActor->VisibilityOn(); + + bool anIsBlocked = ActorList->blockSignals( true ); + + synchronize(); SetCurrentPlaneParam(); + + ActorList->blockSignals( anIsBlocked ); } } @@ -674,20 +695,105 @@ void SMESHGUI_ClippingDlg::ClickOnNew() //======================================================================= void SMESHGUI_ClippingDlg::ClickOnDelete() { - if (!myActor || myPlanes.empty()) + if (myPlanes.empty()) return; int aPlaneIndex = ComboBoxPlanes->currentIndex(); - SMESH::TPlanes::iterator anIter = myPlanes.begin() + aPlaneIndex; - anIter->GetPointer()->myActor->SetVisibility(false); + SMESH::TPlaneDataVector::iterator anIter = myPlanes.begin() + aPlaneIndex; + SMESH::TPlaneData aPlaneData = *anIter; + aPlaneData.Plane.GetPointer()->myActor->SetVisibility(false); myPlanes.erase(anIter); if(AutoApplyCheckBox->isChecked()) ClickOnApply(); - Sinchronize(); - SMESH::RenderViewWindow(SMESH::GetCurrentVtkView()); + synchronize(); + SMESH::RenderViewWindow( myViewWindow ); +} + +//======================================================================= +// function : updateActorItem() +// purpose : +//======================================================================= +void SMESHGUI_ClippingDlg::updateActorItem( QListWidgetItem* theItem, + bool theUpdateSelectAll, + bool theUpdateClippingPlaneMap ) +{ + // update Select All check box + if( theUpdateSelectAll ) { + int aNbItems = ActorList->count(), aNbChecked = 0; + for( int i = 0; i < aNbItems; i++ ) + if( QListWidgetItem* anItem = ActorList->item( i ) ) + if( anItem->checkState() == Qt::Checked ) + aNbChecked++; + + Qt::CheckState aCheckState = Qt::Unchecked; + if( aNbChecked == aNbItems ) + aCheckState = Qt::Checked; + else if( aNbChecked > 0 ) + aCheckState = Qt::PartiallyChecked; + + bool anIsBlocked = SelectAllCheckBox->blockSignals( true ); + SelectAllCheckBox->setCheckState( aCheckState ); + SelectAllCheckBox->blockSignals( anIsBlocked ); + } + + // update clipping plane map + if( theUpdateClippingPlaneMap ) { + int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); + if( ActorItem* anItem = dynamic_cast( theItem ) ) { + if( SMESH_Actor* anActor = anItem->getActor() ) { + SMESH::TPlaneData& aPlaneData = myPlanes[ aCurPlaneIndex ]; + SMESH::TActorList& anActorList = aPlaneData.ActorList; + bool anIsPushed = false; + SMESH::TActorList::iterator anIter = anActorList.begin(); + for ( ; anIter != anActorList.end(); anIter++ ) { + if( anActor == *anIter ) { + anIsPushed = true; + break; + } + } + if( theItem->checkState() == Qt::Checked && !anIsPushed ) + anActorList.push_back( anActor ); + else if( theItem->checkState() == Qt::Unchecked && anIsPushed ) + anActorList.remove( anActor ); + } + } + } +} + +//======================================================================= +// function : onActorItemChanged() +// purpose : +//======================================================================= +void SMESHGUI_ClippingDlg::onActorItemChanged( QListWidgetItem* theItem ) +{ + updateActorItem( theItem, true, true ); + SetCurrentPlaneParam(); +} + +//======================================================================= +// function : onSelectAll() +// purpose : +//======================================================================= +void SMESHGUI_ClippingDlg::onSelectAll( int theState ) +{ + if( theState == Qt::PartiallyChecked ) { + SelectAllCheckBox->setCheckState( Qt::Checked ); + return; + } + + bool anIsBlocked = ActorList->blockSignals( true ); + for( int i = 0, n = ActorList->count(); i < n; i++ ) { + if( QListWidgetItem* anItem = ActorList->item( i ) ) { + anItem->setCheckState( theState == Qt::Checked ? Qt::Checked : Qt::Unchecked ); + updateActorItem( anItem, false, true ); + } + } + SelectAllCheckBox->setTristate( false ); + ActorList->blockSignals( anIsBlocked ); + SetCurrentPlaneParam(); } //======================================================================= @@ -717,10 +823,10 @@ void SMESHGUI_ClippingDlg::onSelectOrientation (int theItem) } //======================================================================= -// function : Sinchronize() +// function : synchronize() // purpose : //======================================================================= -void SMESHGUI_ClippingDlg::Sinchronize() +void SMESHGUI_ClippingDlg::synchronize() { int aNbPlanes = myPlanes.size(); ComboBoxPlanes->clear(); @@ -737,17 +843,22 @@ void SMESHGUI_ClippingDlg::Sinchronize() bool anIsControlsEnable = (aPos >= 0); if (anIsControlsEnable) { onSelectPlane(aPos); + updateActorList(); } else { ComboBoxPlanes->addItem(tr("NO_PLANES")); + ActorList->clear(); SpinBoxRot1->SetValue(0.0); SpinBoxRot2->SetValue(0.0); SpinBoxDistance->SetValue(0.5); } + ActorList->setEnabled(anIsControlsEnable); + SelectAllCheckBox->setEnabled(anIsControlsEnable); buttonDelete->setEnabled(anIsControlsEnable); - buttonApply->setEnabled(anIsControlsEnable); - PreviewCheckBox->setEnabled(anIsControlsEnable); - AutoApplyCheckBox->setEnabled(anIsControlsEnable); + // the following 3 controls should be enabled + //buttonApply->setEnabled(anIsControlsEnable); + //PreviewCheckBox->setEnabled(anIsControlsEnable); + //AutoApplyCheckBox->setEnabled(anIsControlsEnable); ComboBoxOrientation->setEnabled(anIsControlsEnable); SpinBoxDistance->setEnabled(anIsControlsEnable); SpinBoxRot1->setEnabled(anIsControlsEnable); @@ -775,7 +886,8 @@ void SMESHGUI_ClippingDlg::SetCurrentPlaneParam() int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); - OrientedPlane* aPlane = myPlanes[aCurPlaneIndex].GetPointer(); + SMESH::TPlaneData aPlaneData = myPlanes[aCurPlaneIndex]; + SMESH::OrientedPlane* aPlane = aPlaneData.Plane.GetPointer(); vtkFloatingPointType aNormal[3]; SMESH::Orientation anOrientation; @@ -833,52 +945,69 @@ void SMESHGUI_ClippingDlg::SetCurrentPlaneParam() aPlane->SetOrientation(anOrientation); aPlane->SetDistance(getDistance()); - myActor->SetPlaneParam(aNormal, getDistance(), aPlane); - - vtkDataSet* aDataSet = myActor->GetInput(); - vtkFloatingPointType *aPnt = aDataSet->GetCenter(); - - vtkFloatingPointType* anOrigin = aPlane->GetOrigin(); - vtkFloatingPointType aDel = aDataSet->GetLength()/2.0; - - vtkFloatingPointType aDelta[2][3] = {{aDir[0][0]*aDel, aDir[0][1]*aDel, aDir[0][2]*aDel}, - {aDir[1][0]*aDel, aDir[1][1]*aDel, aDir[1][2]*aDel}}; - vtkFloatingPointType aParam, aPnt0[3], aPnt1[3], aPnt2[3]; - - vtkFloatingPointType aPnt01[3] = {aPnt[0] - aDelta[0][0] - aDelta[1][0], - aPnt[1] - aDelta[0][1] - aDelta[1][1], - aPnt[2] - aDelta[0][2] - aDelta[1][2]}; - vtkFloatingPointType aPnt02[3] = {aPnt01[0] + aNormal[0], - aPnt01[1] + aNormal[1], - aPnt01[2] + aNormal[2]}; - vtkPlane::IntersectWithLine(aPnt01,aPnt02,aNormal,anOrigin,aParam,aPnt0); - - vtkFloatingPointType aPnt11[3] = {aPnt[0] - aDelta[0][0] + aDelta[1][0], - aPnt[1] - aDelta[0][1] + aDelta[1][1], - aPnt[2] - aDelta[0][2] + aDelta[1][2]}; - vtkFloatingPointType aPnt12[3] = {aPnt11[0] + aNormal[0], - aPnt11[1] + aNormal[1], - aPnt11[2] + aNormal[2]}; - vtkPlane::IntersectWithLine(aPnt11,aPnt12,aNormal,anOrigin,aParam,aPnt1); - - vtkFloatingPointType aPnt21[3] = {aPnt[0] + aDelta[0][0] - aDelta[1][0], - aPnt[1] + aDelta[0][1] - aDelta[1][1], - aPnt[2] + aDelta[0][2] - aDelta[1][2]}; - vtkFloatingPointType aPnt22[3] = {aPnt21[0] + aNormal[0], - aPnt21[1] + aNormal[1], - aPnt21[2] + aNormal[2]}; - vtkPlane::IntersectWithLine(aPnt21,aPnt22,aNormal,anOrigin,aParam,aPnt2); - - vtkPlaneSource* aPlaneSource = aPlane->myPlaneSource; - aPlaneSource->SetNormal(aNormal[0],aNormal[1],aNormal[2]); - aPlaneSource->SetOrigin(aPnt0[0],aPnt0[1],aPnt0[2]); - aPlaneSource->SetPoint1(aPnt1[0],aPnt1[1],aPnt1[2]); - aPlaneSource->SetPoint2(aPnt2[0],aPnt2[1],aPnt2[2]); + SMESH::TActorList anActorList = aPlaneData.ActorList; + + vtkFloatingPointType aBounds[6]; + vtkFloatingPointType anOrigin[3]; + bool anIsOk = SMESH::ComputeClippingPlaneParameters( anActorList, + aNormal, + getDistance(), + aBounds, + anOrigin ); + + aPlane->myActor->SetVisibility( anIsOk && PreviewCheckBox->isChecked() ); + + if( anIsOk ) { + aPlane->SetNormal( aNormal ); + aPlane->SetOrigin( anOrigin ); + + vtkFloatingPointType aPnt[3] = { ( aBounds[0] + aBounds[1] ) / 2., + ( aBounds[2] + aBounds[3] ) / 2., + ( aBounds[4] + aBounds[5] ) / 2. }; + + vtkFloatingPointType aDel = pow( pow( aBounds[1] - aBounds[0], 2 ) + + pow( aBounds[3] - aBounds[2], 2 ) + + pow( aBounds[5] - aBounds[4], 2 ), 0.5 ); + + vtkFloatingPointType aDelta[2][3] = {{aDir[0][0]*aDel, aDir[0][1]*aDel, aDir[0][2]*aDel}, + {aDir[1][0]*aDel, aDir[1][1]*aDel, aDir[1][2]*aDel}}; + vtkFloatingPointType aParam, aPnt0[3], aPnt1[3], aPnt2[3]; + + vtkFloatingPointType aPnt01[3] = {aPnt[0] - aDelta[0][0] - aDelta[1][0], + aPnt[1] - aDelta[0][1] - aDelta[1][1], + aPnt[2] - aDelta[0][2] - aDelta[1][2]}; + vtkFloatingPointType aPnt02[3] = {aPnt01[0] + aNormal[0], + aPnt01[1] + aNormal[1], + aPnt01[2] + aNormal[2]}; + vtkPlane::IntersectWithLine(aPnt01,aPnt02,aNormal,anOrigin,aParam,aPnt0); + + vtkFloatingPointType aPnt11[3] = {aPnt[0] - aDelta[0][0] + aDelta[1][0], + aPnt[1] - aDelta[0][1] + aDelta[1][1], + aPnt[2] - aDelta[0][2] + aDelta[1][2]}; + vtkFloatingPointType aPnt12[3] = {aPnt11[0] + aNormal[0], + aPnt11[1] + aNormal[1], + aPnt11[2] + aNormal[2]}; + vtkPlane::IntersectWithLine(aPnt11,aPnt12,aNormal,anOrigin,aParam,aPnt1); + + vtkFloatingPointType aPnt21[3] = {aPnt[0] + aDelta[0][0] - aDelta[1][0], + aPnt[1] + aDelta[0][1] - aDelta[1][1], + aPnt[2] + aDelta[0][2] - aDelta[1][2]}; + vtkFloatingPointType aPnt22[3] = {aPnt21[0] + aNormal[0], + aPnt21[1] + aNormal[1], + aPnt21[2] + aNormal[2]}; + vtkPlane::IntersectWithLine(aPnt21,aPnt22,aNormal,anOrigin,aParam,aPnt2); + + vtkPlaneSource* aPlaneSource = aPlane->myPlaneSource; + aPlaneSource->SetNormal(aNormal[0],aNormal[1],aNormal[2]); + aPlaneSource->SetOrigin(aPnt0[0],aPnt0[1],aPnt0[2]); + aPlaneSource->SetPoint1(aPnt1[0],aPnt1[1],aPnt1[2]); + aPlaneSource->SetPoint2(aPnt2[0],aPnt2[1],aPnt2[2]); + } if(AutoApplyCheckBox->isChecked()) ClickOnApply(); - SMESH::RenderViewWindow(SMESH::GetCurrentVtkView()); + SMESH::RenderViewWindow( myViewWindow ); } //======================================================================= @@ -887,8 +1016,8 @@ void SMESHGUI_ClippingDlg::SetCurrentPlaneParam() //======================================================================= void SMESHGUI_ClippingDlg::OnPreviewToggle (bool theIsToggled) { - std::for_each(myPlanes.begin(),myPlanes.end(),TSetVisiblity(theIsToggled)); - SMESH::RenderViewWindow(SMESH::GetCurrentVtkView()); + std::for_each(myPlanes.begin(),myPlanes.end(),TSetVisibility(theIsToggled)); + SMESH::RenderViewWindow( myViewWindow ); } //================================================================================= @@ -906,3 +1035,124 @@ void SMESHGUI_ClippingDlg::keyPressEvent( QKeyEvent* e ) ClickOnHelp(); } } + +//================================================================================= +// function : initializePlaneData() +// purpose : +//================================================================================= +void SMESHGUI_ClippingDlg::initializePlaneData() +{ + const SMESHGUI_ClippingPlaneInfoMap& aClippingPlaneInfoMap = mySMESHGUI->getClippingPlaneInfoMap(); + SMESHGUI_ClippingPlaneInfoMap::const_iterator anIter1 = aClippingPlaneInfoMap.find( myViewWindow->getViewManager() ); + if( anIter1 != aClippingPlaneInfoMap.end() ) { + const SMESHGUI_ClippingPlaneInfoList& aClippingPlaneInfoList = anIter1->second; + SMESHGUI_ClippingPlaneInfoList::const_iterator anIter2 = aClippingPlaneInfoList.begin(); + for( ; anIter2 != aClippingPlaneInfoList.end(); anIter2++ ) { + const SMESH::ClippingPlaneInfo& aClippingPlaneInfo = *anIter2; + SMESH::TPlane aTPlane( aClippingPlaneInfo.Plane ); + SMESH::TPlaneData aPlaneData( aTPlane, aClippingPlaneInfo.ActorList ); + myPlanes.push_back( aPlaneData ); + } + } + std::for_each( myPlanes.begin(),myPlanes.end(), TSetVisibility( PreviewCheckBox->isChecked() ) ); +} + +//================================================================================= +// function : updateActorList() +// purpose : +//================================================================================= +void SMESHGUI_ClippingDlg::updateActorList() +{ + ActorList->clear(); + + SalomeApp_Study* anAppStudy = SMESHGUI::activeStudy(); + if( !anAppStudy ) + return; + + _PTR(Study) aStudy = anAppStudy->studyDS(); + if( !aStudy ) + return; + + if( !myViewWindow ) + return; + + int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); + const SMESH::TPlaneData& aPlaneData = myPlanes[ aCurPlaneIndex ]; + const SMESH::TActorList& anActorList = aPlaneData.ActorList; + + VTK::ActorCollectionCopy aCopy( myViewWindow->getRenderer()->GetActors() ); + vtkActorCollection* anAllActors = aCopy.GetActors(); + anAllActors->InitTraversal(); + while( vtkActor* aVTKActor = anAllActors->GetNextActor() ) { + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) { + if( anActor->hasIO() ) { + Handle(SALOME_InteractiveObject) anIO = anActor->getIO(); + if( _PTR(SObject) aSObj = aStudy->FindObjectID( anIO->getEntry() ) ) { + bool anIsChecked = false; + SMESH::TActorList::const_iterator anIter = anActorList.begin(); + for ( ; anIter != anActorList.end(); anIter++ ) { + if( vtkActor* aVTKActorRef = *anIter ) { + if( SMESH_Actor* anActorRef = SMESH_Actor::SafeDownCast( aVTKActorRef ) ) { + if( anActorRef == anActor ) { + anIsChecked = true; + break; + } + } + } + } + QString aName = QString( aSObj->GetName().c_str() ); + QListWidgetItem* anItem = new ActorItem( anActor, aName, ActorList ); + anItem->setCheckState( anIsChecked ? Qt::Checked : Qt::Unchecked ); + updateActorItem( anItem, true, false ); + } + } + } + } +} + +//================================================================================= +// function : getCurrentActors() +// purpose : +//================================================================================= +SMESH::TActorList SMESHGUI_ClippingDlg::getCurrentActors() +{ + SMESH::TActorList anActorList; + for( int i = 0, n = ActorList->count(); i < n; i++ ) + if( ActorItem* anItem = dynamic_cast( ActorList->item( i ) ) ) + if( anItem->checkState() == Qt::Checked ) + if( SMESH_Actor* anActor = anItem->getActor() ) + anActorList.push_back( anActor ); + return anActorList; +} + +//================================================================================= +// function : dumpPlaneData() +// purpose : +//================================================================================= +void SMESHGUI_ClippingDlg::dumpPlaneData() const +{ + printf( "----------- Plane Data -----------\n" ); + int anId = 1; + SMESH::TPlaneDataVector::const_iterator anIter1 = myPlanes.begin(); + for ( ; anIter1 != myPlanes.end(); anIter1++, anId++ ) { + SMESH::TPlaneData aPlaneData = *anIter1; + SMESH::TPlane aPlane = aPlaneData.Plane; + vtkFloatingPointType* aNormal = aPlane->GetNormal(); + vtkFloatingPointType* anOrigin = aPlane->GetOrigin(); + printf( "Plane N%d:\n", anId ); + printf( " Normal = ( %f, %f, %f )\n", aNormal[0], aNormal[1], aNormal[2] ); + printf( " Origin = ( %f, %f, %f )\n", anOrigin[0], anOrigin[1], anOrigin[2] ); + + SMESH::TActorList anActorList = aPlaneData.ActorList; + SMESH::TActorList::const_iterator anIter2 = anActorList.begin(); + for ( ; anIter2 != anActorList.end(); anIter2++ ) { + if( vtkActor* aVTKActor = *anIter2 ) { + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) + printf( " - Actor: '%s'\n", anActor->getName() ); + } + else + printf( " - Actor: NULL\n"); + } + } + printf( "----------------------------------\n" ); +} diff --git a/src/SMESHGUI/SMESHGUI_ClippingDlg.h b/src/SMESHGUI/SMESHGUI_ClippingDlg.h index 0c70ca9c2..87a4b7b9d 100644 --- a/src/SMESHGUI/SMESHGUI_ClippingDlg.h +++ b/src/SMESHGUI/SMESHGUI_ClippingDlg.h @@ -35,31 +35,91 @@ // Qt includes #include +#include // VTK includes +#include #include // STL includes +#include +#include #include class QLabel; class QPushButton; class QCheckBox; class QComboBox; -class LightApp_SelectionMgr; -class SVTK_Selector; +class QListWidget; +class QListWidgetItem; +class SALOME_Actor; class SMESHGUI; class SMESH_Actor; -class OrientedPlane; class SMESHGUI_SpinBox; +class vtkActor; +class vtkDataSetMapper; +class vtkPlaneSource; namespace SMESH { - typedef vtkSmartPointer TVTKPlane; - typedef std::vector TPlanes; enum Orientation { XY, YZ, ZX }; -}; + class OrientedPlane: public vtkPlane + { + QPointer myViewWindow; + vtkDataSetMapper* myMapper; + + public: + static OrientedPlane *New(); + static OrientedPlane *New(SVTK_ViewWindow* theViewWindow); + vtkTypeMacro (OrientedPlane, vtkPlane); + + SMESH::Orientation myOrientation; + float myDistance; + double myAngle[2]; + + vtkPlaneSource* myPlaneSource; + SALOME_Actor *myActor; + + void SetOrientation (SMESH::Orientation theOrientation) { myOrientation = theOrientation; } + SMESH::Orientation GetOrientation() { return myOrientation; } + + void SetDistance (float theDistance) { myDistance = theDistance; } + float GetDistance() { return myDistance; } + + void ShallowCopy (OrientedPlane* theOrientedPlane); + + protected: + OrientedPlane(SVTK_ViewWindow* theViewWindow); + OrientedPlane(); + + void Init(); + + ~OrientedPlane(); + private: + // Not implemented. + OrientedPlane (const OrientedPlane&); + void operator= (const OrientedPlane&); + }; + + typedef vtkSmartPointer TPlane; + typedef std::list TActorList; + + struct TPlaneData + { + TPlaneData( TPlane thePlane, + TActorList theActorList ) + { + Plane = thePlane; + ActorList = theActorList; + } + TPlane Plane; + TActorList ActorList; + }; + + typedef std::vector TPlaneVector; + typedef std::vector TPlaneDataVector; +}; //================================================================================= // class : SMESHGUI_ClippingDlg @@ -70,7 +130,7 @@ class SMESHGUI_EXPORT SMESHGUI_ClippingDlg : public QDialog Q_OBJECT public: - SMESHGUI_ClippingDlg( SMESHGUI* ); + SMESHGUI_ClippingDlg( SMESHGUI*, SVTK_ViewWindow* ); ~SMESHGUI_ClippingDlg(); double getDistance() const; @@ -78,35 +138,42 @@ public: double getRotation1() const; double getRotation2() const; void setRotation( const double, const double ); - void Sinchronize(); // used in SMESHGUI::restoreVisualParameters() to avoid // declaration of OrientedPlane outside of SMESHGUI_ClippingDlg.cxx - static void AddPlane (SMESH_Actor* theActor, - SVTK_ViewWindow* theViewWindow, - SMESH::Orientation theOrientation, - double theDistance, - vtkFloatingPointType theAngle[2]); - - static void GetPlaneParam (SMESH_Actor* theActor, - int thePlaneIndex, - SMESH::Orientation& theOrientation, - double& theDistance, - vtkFloatingPointType* theAngle); + static SMESH::OrientedPlane* AddPlane (SMESH::TActorList theActorList, + SVTK_ViewWindow* theViewWindow, + SMESH::Orientation theOrientation, + double theDistance, + const vtkFloatingPointType theAngle[2]); protected: void keyPressEvent( QKeyEvent* ); private: - LightApp_SelectionMgr* mySelectionMgr; - SVTK_Selector* mySelector; + void initializePlaneData(); + + void synchronize(); + + void updateActorList(); + SMESH::TActorList getCurrentActors(); + + void updateActorItem( QListWidgetItem* theItem, + bool theUpdateSelectAll, + bool theUpdateClippingPlaneMap ); + + void dumpPlaneData() const; + +private: SMESHGUI* mySMESHGUI; - SMESH_Actor* myActor; - SMESH::TPlanes myPlanes; + SVTK_ViewWindow* myViewWindow; + SMESH::TPlaneDataVector myPlanes; QComboBox* ComboBoxPlanes; QPushButton* buttonNew; QPushButton* buttonDelete; + QListWidget* ActorList; + QCheckBox* SelectAllCheckBox; QLabel* TextLabelOrientation; QComboBox* ComboBoxOrientation; QLabel* TextLabelDistance; @@ -129,9 +196,10 @@ public slots: void onSelectPlane( int ); void ClickOnNew(); void ClickOnDelete(); + void onActorItemChanged( QListWidgetItem* ); + void onSelectAll( int ); void onSelectOrientation( int ); void SetCurrentPlaneParam(); - void onSelectionChanged(); void OnPreviewToggle( bool ); void ClickOnOk(); void ClickOnCancel(); diff --git a/src/SMESHGUI/SMESHGUI_ComputeDlg.cxx b/src/SMESHGUI/SMESHGUI_ComputeDlg.cxx index ccd700190..b31a1b8e9 100644 --- a/src/SMESHGUI/SMESHGUI_ComputeDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ComputeDlg.cxx @@ -98,6 +98,7 @@ #define COLONIZE(str) (QString(str).contains(":") > 0 ? QString(str) : QString(str) + " :" ) +/* OBSOLETE static void addSeparator( QWidget* parent ) { QGridLayout* l = qobject_cast( parent->layout() ); @@ -109,6 +110,7 @@ static void addSeparator( QWidget* parent ) l->addWidget( hline, row, i ); } } +*/ enum TCol { COL_ALGO = 0, COL_SHAPE, COL_ERROR, COL_SHAPEID, COL_PUBLISHED, COL_BAD_MESH, NB_COLUMNS @@ -734,25 +736,38 @@ void SMESHGUI_BaseComputeOp::computeMesh() // SHOW MESH // NPAL16631: if ( getSMESHGUI()->automaticUpdate() ) - if ( !memoryLack && getSMESHGUI()->automaticUpdate() ) + SUIT_ResourceMgr* resMgr = SMESH::GetResourceMgr( SMESHGUI::GetSMESHGUI() ); + long newSize = myMesh->NbElements(); + long limitSize = resMgr->integerValue( "SMESH", "update_limit", 500000 ); + bool limitExceeded; + if ( !memoryLack ) { - try { + if ( getSMESHGUI()->automaticUpdate( newSize, &limitExceeded ) ) + { + try { #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 - OCC_CATCH_SIGNALS; + OCC_CATCH_SIGNALS; #endif - SMESH::Update(myIObject, true); - } - catch (...) { + SMESH::Update(myIObject, true); + } + catch (...) { #ifdef _DEBUG_ - MESSAGE ( "Exception thrown during mesh visualization" ); + MESSAGE ( "Exception thrown during mesh visualization" ); #endif - if ( SMDS_Mesh::CheckMemory(true) ) { // has memory to show warning? - SMESH::OnVisuException(); - } - else { - memoryLack = true; - } + if ( SMDS_Mesh::CheckMemory(true) ) { // has memory to show warning? + SMESH::OnVisuException(); + } + else { + memoryLack = true; + } + } } + else if ( limitExceeded ) + { + SUIT_MessageBox::warning( desktop(), + tr( "SMESH_WRN_WARNING" ), + tr( "SMESH_WRN_SIZE_LIMIT_EXCEEDED" ).arg( newSize ).arg( limitSize ) ); + } } LightApp_SelectionMgr *Sel = selectionMgr(); if ( Sel ) @@ -804,7 +819,7 @@ void SMESHGUI_BaseComputeOp::computeMesh() void SMESHGUI_BaseComputeOp::showComputeResult( const bool theMemoryLack, const bool theNoCompError, SMESH::compute_error_array_var& theCompErrors, - const bool theNoHypoError, + const bool theNoHypoError, const QString& theHypErrors ) { bool hasShape = myMesh->HasShapeToMesh(); @@ -1562,6 +1577,7 @@ void SMESHGUI_PrecomputeOp::onPreview() SMESH::MeshPreviewStruct_var previewData = gen->Precompute(myMesh, myMainShape, (SMESH::Dimension)dim, aShapesId); + SMESH::MeshPreviewStruct* previewRes = previewData._retn(); if ( previewRes && previewRes->nodesXYZ.length() > 0 ) { diff --git a/src/SMESHGUI/SMESHGUI_ComputeDlg.h b/src/SMESHGUI/SMESHGUI_ComputeDlg.h index 618db50c5..ee268a4d4 100644 --- a/src/SMESHGUI/SMESHGUI_ComputeDlg.h +++ b/src/SMESHGUI/SMESHGUI_ComputeDlg.h @@ -53,8 +53,6 @@ class SMESHGUI_MeshInfosBox; class SMESHGUI_PrecomputeDlg; class SMESHGUI_MeshEditPreview; -class SMESH::compute_error_array; - namespace SMESH { class TShapeDisplayer; diff --git a/src/SMESHGUI/SMESHGUI_CreatePolyhedralVolumeDlg.cxx b/src/SMESHGUI/SMESHGUI_CreatePolyhedralVolumeDlg.cxx index 864537e84..7d65ad01d 100644 --- a/src/SMESHGUI/SMESHGUI_CreatePolyhedralVolumeDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_CreatePolyhedralVolumeDlg.cxx @@ -456,22 +456,22 @@ void SMESHGUI_CreatePolyhedralVolumeDlg::ClickOnApply() SMESH::SMESH_GroupBase_var aGroup; int idx = 0; if( addToGroup ) { - aGroupName = ComboBox_GroupName->currentText(); - for ( int i = 1; i < ComboBox_GroupName->count(); i++ ) { - QString aName = ComboBox_GroupName->itemText( i ); - if ( aGroupName == aName && ( i == ComboBox_GroupName->currentIndex() || idx == 0 ) ) - idx = i; - } - if ( idx > 0 ) { - SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( myGroups[idx-1] ); - if ( !aGeomGroup->_is_nil() ) { - int res = SUIT_MessageBox::question( this, tr( "SMESH_WRN_WARNING" ), - tr( "MESH_STANDALONE_GRP_CHOSEN" ).arg( aGroupName ), - tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ); - if ( res == 1 ) return; - } - aGroup = myGroups[idx-1]; - } + aGroupName = ComboBox_GroupName->currentText(); + for ( int i = 1; i < ComboBox_GroupName->count(); i++ ) { + QString aName = ComboBox_GroupName->itemText( i ); + if ( aGroupName == aName && ( i == ComboBox_GroupName->currentIndex() || idx == 0 ) ) + idx = i; + } + if ( idx > 0 ) { + SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( myGroups[idx-1] ); + if ( !aGeomGroup->_is_nil() ) { + int res = SUIT_MessageBox::question( this, tr( "SMESH_WRN_WARNING" ), + tr( "MESH_STANDALONE_GRP_CHOSEN" ).arg( aGroupName ), + tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ); + if ( res == 1 ) return; + } + aGroup = myGroups[idx-1]; + } } if (GetConstructorId() == 0) @@ -535,28 +535,28 @@ void SMESHGUI_CreatePolyhedralVolumeDlg::ClickOnApply() } if ( anElemId != -1 && addToGroup && !aGroupName.isEmpty() ) { - SMESH::SMESH_Group_var aGroupUsed; - if ( aGroup->_is_nil() ) { - // create new group - aGroupUsed = SMESH::AddGroup( myMesh, SMESH::VOLUME, aGroupName ); - if ( !aGroupUsed->_is_nil() ) { - myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroupUsed)); - ComboBox_GroupName->addItem( aGroupName ); - } - } - else { - SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGroup ); - if ( !aGeomGroup->_is_nil() ) { - aGroupUsed = myMesh->ConvertToStandalone( aGeomGroup ); - if ( !aGroupUsed->_is_nil() && idx > 0 ) { - myGroups[idx-1] = SMESH::SMESH_GroupBase::_duplicate(aGroupUsed); - SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); - } - } - else - aGroupUsed = SMESH::SMESH_Group::_narrow( aGroup ); - } - + SMESH::SMESH_Group_var aGroupUsed; + if ( aGroup->_is_nil() ) { + // create new group + aGroupUsed = SMESH::AddGroup( myMesh, SMESH::VOLUME, aGroupName ); + if ( !aGroupUsed->_is_nil() ) { + myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroupUsed)); + ComboBox_GroupName->addItem( aGroupName ); + } + } + else { + SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGroup ); + if ( !aGeomGroup->_is_nil() ) { + aGroupUsed = myMesh->ConvertToStandalone( aGeomGroup ); + if ( !aGroupUsed->_is_nil() && idx > 0 ) { + myGroups[idx-1] = SMESH::SMESH_GroupBase::_duplicate(aGroupUsed); + SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); + } + } + else + aGroupUsed = SMESH::SMESH_Group::_narrow( aGroup ); + } + if ( !aGroupUsed->_is_nil() ) { SMESH::long_array_var anIdList = new SMESH::long_array; anIdList->length( 1 ); @@ -771,10 +771,10 @@ void SMESHGUI_CreatePolyhedralVolumeDlg::SelectionIntoArgument() for ( int i = 0, n = aListOfGroups.length(); i < n; i++ ) { SMESH::SMESH_GroupBase_var aGroup = aListOfGroups[i]; if ( !aGroup->_is_nil() && aGroup->GetType() == SMESH::VOLUME ) { - QString aGroupName( aGroup->GetName() ); - if ( !aGroupName.isEmpty() ) { - myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroup)); - ComboBox_GroupName->addItem( aGroupName ); + QString aGroupName( aGroup->GetName() ); + if ( !aGroupName.isEmpty() ) { + myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroup)); + ComboBox_GroupName->addItem( aGroupName ); } } } diff --git a/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx b/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx new file mode 100644 index 000000000..a2a0afd9c --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx @@ -0,0 +1,580 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_DuplicateNodesDlg.cxx +// Author : Michael ZORIN, Open CASCADE S.A.S. + +// SMESH includes +#include "SMESHGUI_DuplicateNodesDlg.h" + +#include "SMESHGUI.h" +#include "SMESHGUI_Utils.h" +#include "SMESHGUI_VTKUtils.h" + +#include + +// SALOME GUI includes +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +// Qt includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// IDL includes +#include +#include CORBA_SERVER_HEADER(SMESH_MeshEditor) + +#define SPACING 6 +#define MARGIN 11 + + +/*! + \brief Constructor + \param theModule Mesh module instance +*/ +SMESHGUI_DuplicateNodesDlg::SMESHGUI_DuplicateNodesDlg( SMESHGUI* theModule ) + : QDialog( SMESH::GetDesktop( theModule ) ), + mySMESHGUI( theModule ), + mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ) +{ + // Dialog attributes + setModal(false); + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowTitle(tr("SMESH_DUPLICATE_TITLE")); + setSizeGripEnabled(true); + + // Icons for the dialog operation modes and selection button + SUIT_ResourceMgr* aResMgr = SMESH::GetResourceMgr( mySMESHGUI ); + QPixmap iconWithoutElem (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_DUPLICATE_NODES"))); + QPixmap iconWithElem (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_DUPLICATE_NODES_WITH_ELEM"))); + QPixmap iconSelect (aResMgr->loadPixmap("SMESH", tr("ICON_SELECT"))); + + // Main layout + QVBoxLayout* aMainLayout = new QVBoxLayout(this); + aMainLayout->setSpacing(SPACING); + aMainLayout->setMargin(MARGIN); + + // Operation modes selector + QGroupBox* aConstructorsBox = new QGroupBox(tr("DUPLICATION_MODE"), this); + myGroupConstructors = new QButtonGroup(this); + QHBoxLayout* aConstructorsBoxLayout = new QHBoxLayout(aConstructorsBox); + aConstructorsBoxLayout->setSpacing(SPACING); + aConstructorsBoxLayout->setMargin(MARGIN); + + QRadioButton* aRadioButton1 = new QRadioButton(aConstructorsBox); + aRadioButton1->setIcon(iconWithoutElem); + QRadioButton* aRadioButton2 = new QRadioButton(aConstructorsBox); + aRadioButton2->setIcon(iconWithElem); + + aConstructorsBoxLayout->addWidget(aRadioButton1); + aConstructorsBoxLayout->addWidget(aRadioButton2); + myGroupConstructors->addButton(aRadioButton1, 0); + myGroupConstructors->addButton(aRadioButton2, 1); + + // Arguments + myGroupArguments = new QGroupBox(this); + QGridLayout* aGroupArgumentsLayout = new QGridLayout(myGroupArguments); + aGroupArgumentsLayout->setSpacing(SPACING); + aGroupArgumentsLayout->setMargin(MARGIN); + + myTextLabel1 = new QLabel(myGroupArguments); + mySelectButton1 = new QPushButton(myGroupArguments); + mySelectButton1->setIcon(iconSelect); + myLineEdit1 = new QLineEdit(myGroupArguments); + myLineEdit1->setReadOnly(true); + + myTextLabel2 = new QLabel(myGroupArguments); + mySelectButton2 = new QPushButton(myGroupArguments); + mySelectButton2->setIcon(iconSelect); + myLineEdit2 = new QLineEdit(myGroupArguments); + myLineEdit2->setReadOnly(true); + + myTextLabel3 = new QLabel(myGroupArguments); + mySelectButton3 = new QPushButton(myGroupArguments); + mySelectButton3->setIcon(iconSelect); + myLineEdit3 = new QLineEdit(myGroupArguments); + myLineEdit3->setReadOnly(true); + + myCheckBoxNewGroup = new QCheckBox(tr("CONSTRUCT_NEW_GROUP_NODES"), myGroupArguments); + + aGroupArgumentsLayout->addWidget(myTextLabel1, 0, 0); + aGroupArgumentsLayout->addWidget(mySelectButton1, 0, 1); + aGroupArgumentsLayout->addWidget(myLineEdit1, 0, 2); + aGroupArgumentsLayout->addWidget(myTextLabel2, 1, 0); + aGroupArgumentsLayout->addWidget(mySelectButton2, 1, 1); + aGroupArgumentsLayout->addWidget(myLineEdit2, 1, 2); + aGroupArgumentsLayout->addWidget(myTextLabel3, 2, 0); + aGroupArgumentsLayout->addWidget(mySelectButton3, 2, 1); + aGroupArgumentsLayout->addWidget(myLineEdit3, 2, 2); + aGroupArgumentsLayout->addWidget(myCheckBoxNewGroup, 3, 0); + aGroupArgumentsLayout->setRowStretch(4, 1); + + // Buttons + QGroupBox* aGroupButtons = new QGroupBox(this); + QHBoxLayout* aGroupButtonsLayout = new QHBoxLayout(aGroupButtons); + aGroupButtonsLayout->setSpacing(SPACING); + aGroupButtonsLayout->setMargin(MARGIN); + + myButtonOk = new QPushButton(tr("SMESH_BUT_APPLY_AND_CLOSE"), aGroupButtons); + myButtonOk->setAutoDefault(true); + myButtonOk->setDefault(true); + myButtonApply = new QPushButton(tr("SMESH_BUT_APPLY"), aGroupButtons); + myButtonApply->setAutoDefault(true); + myButtonClose = new QPushButton(tr("SMESH_BUT_CLOSE"), aGroupButtons); + myButtonClose->setAutoDefault(true); + myButtonHelp = new QPushButton(tr("SMESH_BUT_HELP"), aGroupButtons); + myButtonHelp->setAutoDefault(true); + + aGroupButtonsLayout->addWidget(myButtonOk); + aGroupButtonsLayout->addSpacing(10); + aGroupButtonsLayout->addWidget(myButtonApply); + aGroupButtonsLayout->addSpacing(10); + aGroupButtonsLayout->addStretch(); + aGroupButtonsLayout->addWidget(myButtonClose); + aGroupButtonsLayout->addWidget(myButtonHelp); + + // Add mode selector, arguments and buttons to the main layout + aMainLayout->addWidget(aConstructorsBox); + aMainLayout->addWidget(myGroupArguments); + aMainLayout->addWidget(aGroupButtons); + + // Initialize the dialog + Init(); + + // Help file name + myHelpFileName = "double_nodes_page.html"; + + // Signals and slots connections + connect(myGroupConstructors, SIGNAL(buttonClicked(int)), SLOT(onConstructorsClicked(int))); + + connect(mySelectButton1, SIGNAL (clicked()), this, SLOT(onEditCurrentArgument())); + connect(mySelectButton2, SIGNAL (clicked()), this, SLOT(onEditCurrentArgument())); + connect(mySelectButton3, SIGNAL (clicked()), this, SLOT(onEditCurrentArgument())); + + connect(myButtonOk, SIGNAL(clicked()), this, SLOT(onOk())); + connect(myButtonClose, SIGNAL(clicked()), this, SLOT(onClose())); + connect(myButtonApply, SIGNAL(clicked()), this, SLOT(onApply())); + connect(myButtonHelp, SIGNAL(clicked()), this, SLOT(onHelp())); + + connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), SLOT(onSelectionChanged())); + + connect(mySMESHGUI, SIGNAL (SignalDeactivateActiveDialog()), this, SLOT(onDeactivate())); + connect(mySMESHGUI, SIGNAL (SignalCloseAllDialogs()), this, SLOT(onClose())); +} + +/*! + \brief Destructor +*/ +SMESHGUI_DuplicateNodesDlg::~SMESHGUI_DuplicateNodesDlg() +{ +} + +/*! + \brief Destructor +*/ +void SMESHGUI_DuplicateNodesDlg::Init() +{ + mySMESHGUI->SetActiveDialogBox((QDialog*)this); + + // Set initial parameters + myBusy = false; + myCurrentLineEdit = myLineEdit1; + + myGroup1 = SMESH::SMESH_GroupBase::_nil(); + myGroup2 = SMESH::SMESH_GroupBase::_nil(); + myGroup3 = SMESH::SMESH_GroupBase::_nil(); + + // Set selection mode + mySelectionMgr->installFilter(new SMESH_TypeFilter(GROUP)); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) + aViewWindow->SetSelectionMode(ActorSelection); + + // Set construction mode + int operationMode = myGroupConstructors->checkedId(); + if (operationMode < 0) { + // The dialog has been just displayed + operationMode = 0; + myGroupConstructors->button(0)->setChecked(true); + } + onConstructorsClicked(operationMode); +} + +/*! + \brief SLOT called to change the dialog operation mode. + \param constructorId id of the radio button in mode selector button group +*/ +void SMESHGUI_DuplicateNodesDlg::onConstructorsClicked (int constructorId) +{ + // Clear all fields + myLineEdit1->clear(); + myLineEdit2->clear(); + myLineEdit3->clear(); + + // Checkbox should be checked by default + myCheckBoxNewGroup->setChecked(true); + + // Set the first field as current + myCurrentLineEdit = myLineEdit1; + myCurrentLineEdit->setFocus(); + + switch (constructorId) { + case 0: + { + // Set text to the group of arguments and to the first two labels + myGroupArguments->setTitle(tr("DUPLICATION_WITHOUT_ELEMS")); + myTextLabel1->setText(tr("GROUP_NODES_TO_DUPLICATE")); + myTextLabel2->setText(tr("GROUP_NODES_TO_REPLACE")); + + // Set checkbox title + myCheckBoxNewGroup->setText(tr("CONSTRUCT_NEW_GROUP_NODES")); + + // Hide the third field + myTextLabel3->hide(); + mySelectButton3->hide(); + myLineEdit3->hide(); + + break; + } + case 1: + { + // Set text to the group of arguments and to all the labels + myGroupArguments->setTitle(tr("DUPLICATION_WITH_ELEMS")); + myTextLabel1->setText(tr("GROUP_ELEMS_TO_DUPLICATE")); + myTextLabel2->setText(tr("GROUP_NODES_NOT_DUPLICATE")); + myTextLabel3->setText(tr("GROUP_ELEMS_TO_REPLACE")); + + // Set checkbox title + myCheckBoxNewGroup->setText(tr("CONSTRUCT_NEW_GROUP_ELEMENTS")); + + // Show the third field + myTextLabel3->show(); + mySelectButton3->show(); + myLineEdit3->show(); + + break; + } + } + + // Process selection + onSelectionChanged(); +} + +/*! + \brief SLOT called to apply changes. +*/ +bool SMESHGUI_DuplicateNodesDlg::onApply() +{ + if (mySMESHGUI->isActiveStudyLocked() || !isValid()) + return false; + + myBusy = true; + + bool toCreateGroup = myCheckBoxNewGroup->isChecked(); + int operationMode = myGroupConstructors->checkedId(); + + // Apply changes + bool result = false; + SUIT_OverrideCursor aWaitCursor; + + try { + SMESH::SMESH_Mesh_ptr aMesh = myGroup1->GetMesh(); + SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor(); + + if (operationMode == 0) { + if (toCreateGroup) { + SMESH::SMESH_GroupBase_ptr aNewGroup = + aMeshEditor->DoubleNodeGroupNew(myGroup1, myGroup2); + if (!CORBA::is_nil(aNewGroup)) + result = true; + } + else + result = aMeshEditor->DoubleNodeGroup(myGroup1, myGroup2); + } + else { + if (toCreateGroup) { + SMESH::SMESH_GroupBase_ptr aNewGroup = + aMeshEditor->DoubleNodeElemGroupNew(myGroup1, myGroup2, myGroup3); + if (!CORBA::is_nil(aNewGroup)) + result = true; + } + else + result = aMeshEditor->DoubleNodeElemGroup(myGroup1, myGroup2, myGroup3); + } + } + catch (const SALOME::SALOME_Exception& S_ex) { + SalomeApp_Tools::QtCatchCorbaException(S_ex); + } + catch ( const std::exception& exc ) { + INFOS( "Follow exception was cought:\n\t" << exc.what() ); + } + catch (...){ + INFOS( "Unknown exception was cought !!!" ); + } + + if (!result) { + SUIT_MessageBox::warning(this, + tr("SMESH_WRN_WARNING"), + tr("SMESH_OPERATION_FAILED")); + myBusy = false; + return false; + } + + // Update GUI + mySelectionMgr->clearSelected(); + SMESH::UpdateView(); + SMESHGUI::Modified(); + mySMESHGUI->updateObjBrowser(true); + + // Reinitialize the dialog + Init(); + + return true; +} + +/*! + \brief SLOT called to apply changes and close the dialog. +*/ +void SMESHGUI_DuplicateNodesDlg::onOk() +{ + if (onApply()) + onClose(); +} + +/*! + \brief SLOT called to close the dialog. +*/ +void SMESHGUI_DuplicateNodesDlg::onClose() +{ + disconnect(mySelectionMgr, 0, this, 0); + disconnect(mySMESHGUI, 0, this, 0); + mySMESHGUI->ResetState(); + mySelectionMgr->clearFilters(); + reject(); +} + +/*! + \brief SLOT called when selection changed. +*/ +void SMESHGUI_DuplicateNodesDlg::onSelectionChanged() +{ + if (myBusy || !isEnabled()) return; + + // Try to get selected group + SALOME_ListIO aList; + mySelectionMgr->selectedObjects( aList ); + int aNbSel = aList.Extent(); + + SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_nil(); + if (aNbSel == 1) { + Handle(SALOME_InteractiveObject) IO = aList.First(); + aGroup = SMESH::IObjectToInterface(IO); + + // Check group type + if (!CORBA::is_nil(aGroup)) { + int operationMode = myGroupConstructors->checkedId(); + SMESH::ElementType aGroupType = aGroup->GetType(); + bool isTypeValid = true; + + if (operationMode == 0) { + if ( (myCurrentLineEdit == myLineEdit1 && aGroupType != SMESH::NODE) || + (myCurrentLineEdit == myLineEdit2 && aGroupType == SMESH::NODE) ) + isTypeValid = false; + } + else if (operationMode == 1) { + if ( (myCurrentLineEdit == myLineEdit1 && aGroupType != SMESH::EDGE && + aGroupType != SMESH::FACE) || + (myCurrentLineEdit == myLineEdit2 && aGroupType != SMESH::NODE) || + (myCurrentLineEdit == myLineEdit3 && aGroupType == SMESH::NODE) ) + isTypeValid = false; + } + + if (!isTypeValid) + aGroup = SMESH::SMESH_GroupBase::_nil(); + } + } + + // Clear current field + myCurrentLineEdit->clear(); + + // Set corresponding SMESH group + if (myCurrentLineEdit == myLineEdit1) { + myGroup1 = SMESH::SMESH_Group::_narrow(aGroup); + } + else if (myCurrentLineEdit == myLineEdit2) { + myGroup2 = SMESH::SMESH_Group::_narrow(aGroup); + } + else if (myCurrentLineEdit == myLineEdit3) { + myGroup3 = SMESH::SMESH_Group::_narrow(aGroup); + } + + // Set group name + if (!CORBA::is_nil(aGroup)) + myCurrentLineEdit->setText(aGroup->GetName()); + + // Enable/disable "Apply and Close" and "Apply" buttons + bool isDataValid = isValid(); + myButtonOk->setEnabled(isDataValid); + myButtonApply->setEnabled(isDataValid); +} + +/*! + \brief SLOT called when selection button clicked. +*/ +void SMESHGUI_DuplicateNodesDlg::onEditCurrentArgument() +{ + QPushButton* send = (QPushButton*)sender(); + + // Set current field for edition + if (send == mySelectButton1) { + myCurrentLineEdit = myLineEdit1; + } + else if (send == mySelectButton2) { + myCurrentLineEdit = myLineEdit2; + } + else if (send == mySelectButton3) { + myCurrentLineEdit = myLineEdit3; + } + + myCurrentLineEdit->setFocus(); + onSelectionChanged(); +} + +/*! + \brief Check if the input data is valid. + \return \c true id the data is valid +*/ +bool SMESHGUI_DuplicateNodesDlg::isValid() +{ + // Only first group (nodes/elemets to duplicate) is mandatory + bool isValid = !CORBA::is_nil(myGroup1); + + // First (elements to duplicate) and last groups should be defined in the second operation mode + if (isValid && myGroupConstructors->checkedId() == 1) + isValid = !CORBA::is_nil(myGroup3); + + return isValid; +} + + +/*! + \brief SLOT called when dialog shoud be deativated. +*/ +void SMESHGUI_DuplicateNodesDlg::onDeactivate() +{ + if (isEnabled()) { + mySelectionMgr->clearFilters(); + setEnabled(false); + mySMESHGUI->ResetState(); + mySMESHGUI->SetActiveDialogBox(0); + } +} + +/*! + \brief Receive dialog enter events. + Activates the dialog when the mouse cursor enters. + Reimplemented from QWidget class. +*/ +void SMESHGUI_DuplicateNodesDlg::enterEvent (QEvent*) +{ + if ( !isEnabled() ) { + mySMESHGUI->EmitSignalDeactivateDialog(); + setEnabled(true); + mySMESHGUI->SetActiveDialogBox((QDialog*)this); + + // Set selection mode + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) + aViewWindow->SetSelectionMode(ActorSelection); + mySelectionMgr->installFilter(new SMESH_TypeFilter (GROUP)); + } +} + +/*! + \brief Receive close events. + Reimplemented from QWidget class. +*/ +void SMESHGUI_DuplicateNodesDlg::closeEvent (QCloseEvent*) +{ + onClose(); +} + +/*! + \brief Receive key press events. + Reimplemented from QWidget class. +*/ +void SMESHGUI_DuplicateNodesDlg::keyPressEvent( QKeyEvent* e ) +{ + QDialog::keyPressEvent( e ); + if ( e->isAccepted() ) + return; + + if ( e->key() == Qt::Key_F1 ) { + e->accept(); + onHelp(); + } +} + +/*! + \brief Show the dialog help page. +*/ +void SMESHGUI_DuplicateNodesDlg::onHelp() +{ + LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication()); + if (app) + app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName); + else { + QString platform; +#ifdef WIN32 + platform = "winapplication"; +#else + platform = "application"; +#endif + SUIT_MessageBox::warning(this, tr("WRN_WARNING"), + tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE"). + arg(app->resourceMgr()->stringValue("ExternalBrowser", + platform)). + arg(myHelpFileName)); + } +} diff --git a/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.h b/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.h new file mode 100644 index 000000000..974b7d7fa --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.h @@ -0,0 +1,119 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_DuplicateNodesDlg.h +// Author : Michael ZORIN, Open CASCADE S.A.S. +// +#ifndef SMESHGUI_DUPLICATENODESDLG_H +#define SMESHGUI_DUPLICATENODESDLG_H + +// SMESH includes +#include "SMESH_SMESHGUI.hxx" + +// Qt includes +#include + +// IDL includes +#include +#include CORBA_SERVER_HEADER(SMESH_Group) + +class QButtonGroup; +class QGroupBox; +class QLabel; +class QLineEdit; +class QPushButton; +class QCheckBox; + +class LightApp_SelectionMgr; + +class SMESHGUI; + +/*! + \class SMESHGUI_DuplicateNodesDlg + \brief Dialog for duplication of nodes. +*/ +class SMESHGUI_EXPORT SMESHGUI_DuplicateNodesDlg : public QDialog +{ + Q_OBJECT + +public: + SMESHGUI_DuplicateNodesDlg( SMESHGUI* ); + ~SMESHGUI_DuplicateNodesDlg(); + +private: + void Init(); + + bool isValid(); + + void closeEvent( QCloseEvent* ); + void enterEvent( QEvent* ); + void keyPressEvent( QKeyEvent* ); + +private slots: + void onConstructorsClicked( int ); + + void onOk(); + void onClose(); + bool onApply(); + void onHelp(); + + void onEditCurrentArgument(); + void onSelectionChanged(); + + void onDeactivate(); + +private: + QLineEdit* myCurrentLineEdit; + + QButtonGroup* myGroupConstructors; + + QGroupBox* myGroupArguments; + QLabel* myTextLabel1; + QLabel* myTextLabel2; + QLabel* myTextLabel3; + QPushButton* mySelectButton1; + QPushButton* mySelectButton2; + QPushButton* mySelectButton3; + QLineEdit* myLineEdit1; + QLineEdit* myLineEdit2; + QLineEdit* myLineEdit3; + QCheckBox* myCheckBoxNewGroup; + + QPushButton* myButtonOk; + QPushButton* myButtonApply; + QPushButton* myButtonClose; + QPushButton* myButtonHelp; + + SMESHGUI* mySMESHGUI; + LightApp_SelectionMgr* mySelectionMgr; + + SMESH::SMESH_GroupBase_var myGroup1; + SMESH::SMESH_GroupBase_var myGroup2; + SMESH::SMESH_GroupBase_var myGroup3; + + bool myBusy; + + QString myHelpFileName; +}; + +#endif // SMESHGUI_DUPLICATENODESDLG_H diff --git a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx index f9b4af034..ee88f7662 100755 --- a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx @@ -33,6 +33,7 @@ #include "SMESHGUI_Filter.h" #include "SMESHGUI_FilterUtils.h" #include "SMESHGUI_FilterLibraryDlg.h" +#include "SMESHGUI_SpinBox.h" #include #include @@ -160,30 +161,32 @@ public: virtual void SetString(const int, const QString&); void SetEditable(const int, const bool); void SetEditable(const bool); + void SetPrecision(const int, const char* = 0); private: - QMap< int, QLineEdit* > myLineEdits; + QMap< int, QWidget* > myWidgets; }; SMESHGUI_FilterTable::AdditionalWidget::AdditionalWidget (QWidget* theParent) : QWidget(theParent) { QLabel* aLabel = new QLabel(tr("SMESH_TOLERANCE"), this); - myLineEdits[ Tolerance ] = new QLineEdit(this); - QDoubleValidator* aValidator = new QDoubleValidator(myLineEdits[ Tolerance ]); - aValidator->setBottom(0); - myLineEdits[ Tolerance ]->setValidator(aValidator); + + SMESHGUI_SpinBox* sb = new SMESHGUI_SpinBox(this); + sb->setAcceptNames( false ); // No Notebook variables allowed + sb->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); + sb->RangeStepAndValidator( 0., 1.e20, 0.1, "len_tol_precision" ); + myWidgets[ Tolerance ] = sb; QHBoxLayout* aLay = new QHBoxLayout(this); aLay->setSpacing(SPACING); aLay->setMargin(0); aLay->addWidget(aLabel); - aLay->addWidget(myLineEdits[ Tolerance ]); + aLay->addWidget(myWidgets[ Tolerance ]); aLay->addStretch(); - QString aText = QString("%1").arg(Precision::Confusion()); - myLineEdits[ Tolerance ]->setText(aText); + SetDouble( Tolerance, Precision::Confusion() ); } SMESHGUI_FilterTable::AdditionalWidget::~AdditionalWidget() @@ -205,13 +208,18 @@ bool SMESHGUI_FilterTable::AdditionalWidget::IsValid (const bool theMsg) const QList aParams = GetParameters(); QList::const_iterator anIter; for (anIter = aParams.begin(); anIter != aParams.end(); ++anIter) { - const QLineEdit* aWg = myLineEdits[ *anIter ]; - int p = 0; - QString aText = aWg->text(); - if (aWg->isEnabled() && aWg->validator()->validate(aText, p) != QValidator::Acceptable) { - if (theMsg) - SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INSUFFICIENT_DATA"), - tr("SMESHGUI_INVALID_PARAMETERS")); + if ( !myWidgets.contains( *anIter ) ) continue; + bool valid = true; + if ( qobject_cast( myWidgets[ *anIter ] ) ) { + valid = qobject_cast( myWidgets[ *anIter ] )->hasAcceptableInput(); + } + else if ( qobject_cast( myWidgets[ *anIter ] ) ) { + QString foo; + valid = qobject_cast( myWidgets[ *anIter ] )->isValid( foo, false ); + } + if (!valid && theMsg) { + SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INSUFFICIENT_DATA"), + tr("SMESHGUI_INVALID_PARAMETERS")); return false; } } @@ -221,41 +229,78 @@ bool SMESHGUI_FilterTable::AdditionalWidget::IsValid (const bool theMsg) const double SMESHGUI_FilterTable::AdditionalWidget::GetDouble (const int theId) const { - return myLineEdits.contains(theId) ? myLineEdits[ theId ]->text().toDouble() : 0; + double retval = 0; + if ( myWidgets.contains( theId ) ) { + if ( qobject_cast( myWidgets[ theId ] ) ) + retval = qobject_cast( myWidgets[ theId ] )->text().toDouble(); + if ( qobject_cast( myWidgets[ theId ] ) ) + retval = qobject_cast( myWidgets[ theId ] )->GetValue(); + } + return retval; } int SMESHGUI_FilterTable::AdditionalWidget::GetInteger (const int theId) const { - return myLineEdits.contains(theId) ? myLineEdits[ theId ]->text().toInt() : 0; + int retval = 0; + if ( myWidgets.contains( theId ) ) { + if ( qobject_cast( myWidgets[ theId ] ) ) + retval = qobject_cast( myWidgets[ theId ] )->text().toInt(); + if ( qobject_cast( myWidgets[ theId ] ) ) + retval = (int)( qobject_cast( myWidgets[ theId ] )->GetValue() ); + } + return retval; } QString SMESHGUI_FilterTable::AdditionalWidget::GetString (const int theId) const { - return myLineEdits.contains(theId) ? myLineEdits[ theId ]->text() : QString(""); + QString retval = ""; + if ( myWidgets.contains( theId ) ) { + if ( qobject_cast( myWidgets[ theId ] ) ) + retval = qobject_cast( myWidgets[ theId ] )->text(); + if ( qobject_cast( myWidgets[ theId ] ) ) + retval = QString::number( qobject_cast( myWidgets[ theId ] )->GetValue() ); + } + return retval; } void SMESHGUI_FilterTable::AdditionalWidget::SetDouble (const int theId, const double theVal) { - if (myLineEdits.contains(theId)) - myLineEdits[ theId ]->setText(QString("%1").arg(theVal)); + if ( myWidgets.contains( theId ) ) { + if ( qobject_cast( myWidgets[ theId ] ) ) + qobject_cast( myWidgets[ theId ] )->setText( QString::number( theVal ) ); + if ( qobject_cast( myWidgets[ theId ] ) ) + qobject_cast( myWidgets[ theId ] )->SetValue( theVal ); + } } void SMESHGUI_FilterTable::AdditionalWidget::SetInteger (const int theId, const int theVal) { - if (myLineEdits.contains(theId)) - myLineEdits[ theId ]->setText(QString("%1").arg(theVal)); + if ( myWidgets.contains( theId ) ) { + if ( qobject_cast( myWidgets[ theId ] ) ) + qobject_cast( myWidgets[ theId ] )->setText( QString::number( theVal ) ); + if ( qobject_cast( myWidgets[ theId ] ) ) + qobject_cast( myWidgets[ theId ] )->SetValue( (double)theVal ); + } } void SMESHGUI_FilterTable::AdditionalWidget::SetString (const int theId, const QString& theVal) { - if (myLineEdits.contains(theId)) - myLineEdits[ theId ]->setText(theVal); + if ( myWidgets.contains( theId ) ) { + if ( qobject_cast( myWidgets[ theId ] ) ) + qobject_cast( myWidgets[ theId ] )->setText( theVal ); + if ( qobject_cast( myWidgets[ theId ] ) ) + qobject_cast( myWidgets[ theId ] )->SetValue( theVal.toDouble() ); + } } void SMESHGUI_FilterTable::AdditionalWidget::SetEditable (const int theId, const bool isEditable) { - if (myLineEdits.contains(theId)) - myLineEdits[ theId ]->setReadOnly(!isEditable); + if ( myWidgets.contains( theId ) ) { + if ( qobject_cast( myWidgets[ theId ] ) ) + qobject_cast( myWidgets[ theId ] )->setReadOnly( !isEditable ); + if ( qobject_cast( myWidgets[ theId ] ) ) + qobject_cast( myWidgets[ theId ] )->setReadOnly( !isEditable ); + } } void SMESHGUI_FilterTable::AdditionalWidget::SetEditable (const bool isEditable) @@ -266,6 +311,19 @@ void SMESHGUI_FilterTable::AdditionalWidget::SetEditable (const bool isEditable) SetEditable( *anIter, isEditable ); } +void SMESHGUI_FilterTable::AdditionalWidget::SetPrecision(const int theId, const char* precision) +{ + if ( myWidgets.contains( theId ) ) { + if ( qobject_cast( myWidgets[ theId ] ) ) { + SMESHGUI_SpinBox* sb = qobject_cast( myWidgets[ theId ] ); + double val = sb->GetValue(); + double min = pow(10.0, -(sb->decimals())); + sb->RangeStepAndValidator( 0., 1.e20, 0.1, precision ? precision : "len_tol_precision" ); + sb->SetValue( qMax( val, min ) ); + } + } +} + /* Class : SMESHGUI_FilterTable::ComboItem Description : Combo table item. Identificator corresponding to string may be assigned @@ -910,13 +968,16 @@ bool SMESHGUI_FilterTable::IsValid (const bool theMess, const int theEntityType) QtxColorButton* clrBtn = qobject_cast(aTable->cellWidget(i, 2)); if (clrBtn && !clrBtn->color().isValid()) errMsg = tr( "GROUPCOLOR_ERROR" ); - } else if (aCriterion == SMESH::FT_RangeOfIds || - aCriterion == SMESH::FT_BelongToGeom || - aCriterion == SMESH::FT_BelongToPlane || - aCriterion == SMESH::FT_BelongToCylinder || - aCriterion == SMESH::FT_BelongToGenSurface || - aCriterion == SMESH::FT_ElemGeomType || - aCriterion == SMESH::FT_LyingOnGeom) { + } + else if (aCriterion == SMESH::FT_RangeOfIds || + aCriterion == SMESH::FT_BelongToGeom || + aCriterion == SMESH::FT_BelongToPlane || + aCriterion == SMESH::FT_BelongToCylinder || + aCriterion == SMESH::FT_BelongToGenSurface || + aCriterion == SMESH::FT_ElemGeomType || + aCriterion == SMESH::FT_CoplanarFaces || + aCriterion == SMESH::FT_LyingOnGeom) + { if (aTable->text(i, 2).isEmpty()) errMsg = tr( "ERROR" ); } @@ -930,8 +991,8 @@ bool SMESHGUI_FilterTable::IsValid (const bool theMess, const int theEntityType) if (!aRes && aTable->isEditable(i, 2)) errMsg = tr( "ERROR" ); else if (aType == SMESH::EDGE && - GetCriterionType(i, aType) == SMESH::FT_MultiConnection && - aThreshold == 1) + GetCriterionType(i, aType) == SMESH::FT_MultiConnection && + aThreshold == 1) errMsg = tr( "MULTIEDGES_ERROR" ); } @@ -1030,12 +1091,14 @@ void SMESHGUI_FilterTable::GetCriterion (const int theRow, } else if ( aCriterionType == SMESH::FT_ElemGeomType ) theCriterion.Threshold = (double)((ComboItem*)aTable->item(theRow, 2))->value(); + else if ( aCriterionType == SMESH::FT_CoplanarFaces ) + theCriterion.ThresholdID = aTable->text(theRow, 2).toLatin1().constData(); else if ( aCriterionType != SMESH::FT_RangeOfIds && aCriterionType != SMESH::FT_BelongToGeom && aCriterionType != SMESH::FT_BelongToPlane && aCriterionType != SMESH::FT_BelongToCylinder && aCriterionType != SMESH::FT_BelongToGenSurface && - aCriterionType != SMESH::FT_LyingOnGeom) + aCriterionType != SMESH::FT_LyingOnGeom ) { theCriterion.Compare = ((ComboItem*)aTable->item(theRow, 1))->value(); theCriterion.Threshold = aTable->item(theRow, 2)->text().toDouble(); @@ -1101,19 +1164,26 @@ void SMESHGUI_FilterTable::SetCriterion (const int theRow, ComboItem* typeBox = (ComboItem*)aTable->item(theRow, 2); typeBox->setValue( (int)(theCriterion.Threshold + 0.5) ); } + else if (theCriterion.Type == SMESH::FT_CoplanarFaces ) + { + aTable->item( theRow, 2 )->setText( QString( theCriterion.ThresholdID ) ); + } else if (theCriterion.Type != SMESH::FT_RangeOfIds && - theCriterion.Type != SMESH::FT_BelongToGeom && - theCriterion.Type != SMESH::FT_BelongToPlane && - theCriterion.Type != SMESH::FT_BelongToCylinder && - theCriterion.Type != SMESH::FT_BelongToGenSurface && - theCriterion.Type != SMESH::FT_LyingOnGeom && - theCriterion.Type != SMESH::FT_FreeBorders && - theCriterion.Type != SMESH::FT_FreeEdges && - theCriterion.Type != SMESH::FT_FreeNodes && - theCriterion.Type != SMESH::FT_FreeFaces && - theCriterion.Type != SMESH::FT_BadOrientedVolume && - theCriterion.Type != SMESH::FT_LinearOrQuadratic) + theCriterion.Type != SMESH::FT_BelongToGeom && + theCriterion.Type != SMESH::FT_BelongToPlane && + theCriterion.Type != SMESH::FT_BelongToCylinder && + theCriterion.Type != SMESH::FT_BelongToGenSurface && + theCriterion.Type != SMESH::FT_LyingOnGeom && + theCriterion.Type != SMESH::FT_CoplanarFaces && + theCriterion.Type != SMESH::FT_FreeBorders && + theCriterion.Type != SMESH::FT_FreeEdges && + theCriterion.Type != SMESH::FT_FreeNodes && + theCriterion.Type != SMESH::FT_FreeFaces && + theCriterion.Type != SMESH::FT_BadOrientedVolume && + theCriterion.Type != SMESH::FT_LinearOrQuadratic) + { aTable->item( theRow, 2 )->setText(QString("%1").arg(theCriterion.Threshold, 0, 'g', 15)); + } else { aTable->item( theRow, 2 )->setText(QString(theCriterion.ThresholdStr)); @@ -1121,24 +1191,25 @@ void SMESHGUI_FilterTable::SetCriterion (const int theRow, aTable->item( theRow, 5 )->setText( QString( theCriterion.ThresholdID ) ); } - if (theCriterion.Compare == SMESH::FT_EqualTo || - theCriterion.Type == SMESH::FT_BelongToPlane || - theCriterion.Type == SMESH::FT_BelongToCylinder || - theCriterion.Type == SMESH::FT_BelongToGenSurface || - theCriterion.Type == SMESH::FT_BelongToGeom || - theCriterion.Type == SMESH::FT_LyingOnGeom) + if (theCriterion.Compare == SMESH::FT_EqualTo || + theCriterion.Type == SMESH::FT_BelongToPlane || + theCriterion.Type == SMESH::FT_BelongToCylinder || + theCriterion.Type == SMESH::FT_BelongToGenSurface || + theCriterion.Type == SMESH::FT_BelongToGeom || + theCriterion.Type == SMESH::FT_LyingOnGeom || + theCriterion.Type == SMESH::FT_CoplanarFaces) { QTableWidgetItem* anItem = aTable->item(theRow, 0); if (!myAddWidgets.contains(anItem)) { myAddWidgets[ anItem ] = new AdditionalWidget(myWgStack); + myAddWidgets[ anItem ]->SetPrecision( AdditionalWidget::Tolerance, getPrecision( theCriterion.Type ) ); myWgStack->addWidget(myAddWidgets[ anItem ]); } myAddWidgets[ anItem ]->SetDouble(AdditionalWidget::Tolerance, theCriterion.Tolerance); } emit CriterionChanged(theRow, aType); - } //======================================================================= @@ -1266,11 +1337,13 @@ void SMESHGUI_FilterTable::updateAdditionalWidget() ComboItem* anItem = ((ComboItem*)aTable->item(aRow, 0)); int aCriterion = GetCriterionType(aRow); - bool toEnable = ((ComboItem*)aTable->item(aRow, 1))->value() == SMESH::FT_EqualTo && - aCriterion != SMESH::FT_RangeOfIds && - aCriterion != SMESH::FT_FreeEdges && - aCriterion != SMESH::FT_FreeFaces && - aCriterion != SMESH::FT_BadOrientedVolume; + bool toEnable = ((((ComboItem*)aTable->item(aRow, 1))->value() == SMESH::FT_EqualTo && + aCriterion != SMESH::FT_RangeOfIds && + aCriterion != SMESH::FT_FreeEdges && + aCriterion != SMESH::FT_FreeFaces && + aCriterion != SMESH::FT_BadOrientedVolume) + || + aCriterion == SMESH::FT_CoplanarFaces); if (!myAddWidgets.contains(anItem)) { @@ -1279,9 +1352,44 @@ void SMESHGUI_FilterTable::updateAdditionalWidget() } myWgStack->setCurrentWidget(myAddWidgets[ anItem ]); + myAddWidgets[ anItem ]->SetPrecision( AdditionalWidget::Tolerance, getPrecision( aCriterion ) ); myWgStack->setEnabled(toEnable); } +const char* SMESHGUI_FilterTable::getPrecision( const int aType ) +{ + const char* retval = 0; + switch ( aType ) { + case SMESH::FT_AspectRatio: + case SMESH::FT_AspectRatio3D: + case SMESH::FT_Taper: + retval = "parametric_precision"; break; + case SMESH::FT_Warping: + case SMESH::FT_MinimumAngle: + case SMESH::FT_Skew: + case SMESH::FT_CoplanarFaces: + retval = "angle_precision"; break; + case SMESH::FT_Area: + retval = "area_precision"; break; + case SMESH::FT_BelongToGeom: + case SMESH::FT_BelongToPlane: + case SMESH::FT_BelongToCylinder: + case SMESH::FT_BelongToGenSurface: + case SMESH::FT_LyingOnGeom: + retval = "len_tol_precision"; break; + case SMESH::FT_Length: + case SMESH::FT_Length2D: + case SMESH::FT_MaxElementLength2D: + case SMESH::FT_MaxElementLength3D: + retval = "length_precision"; break; + case SMESH::FT_Volume3D: + retval = "vol_precision"; break; + default: + break; + } + return retval; +} + //======================================================================= // name : SMESHGUI_FilterTable::removeAdditionalWidget // Purpose : Remove widgets containing additional parameters from widget @@ -1376,7 +1484,7 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int col, con bool isComboItem = false; if (aTableItem) { int aTableType = aTable->item(row, 2)->type(); - isComboItem = aTableType == aComboType ? true : false; + isComboItem = ( aTableType == aComboType ); } if ( (aCriterionType != SMESH::FT_GroupColor && clrBtn) || @@ -1410,14 +1518,16 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int col, con aTable->blockSignals( isSignalsBlocked ); } - if (aType == SMESH::NODE && aCriterionType == SMESH::FT_FreeNodes || - aType == SMESH::EDGE && aCriterionType == SMESH::FT_FreeBorders || - aType == SMESH::FACE && (aCriterionType == SMESH::FT_FreeEdges || - aCriterionType == SMESH::FT_FreeFaces) || - aType == SMESH::VOLUME && aCriterionType == SMESH::FT_BadOrientedVolume || + if ((aType == SMESH::NODE && aCriterionType == SMESH::FT_FreeNodes ) || + (aType == SMESH::EDGE && aCriterionType == SMESH::FT_FreeBorders ) || + (aType == SMESH::FACE && (aCriterionType == SMESH::FT_FreeEdges || + aCriterionType == SMESH::FT_FreeFaces)) || + (aType == SMESH::VOLUME && aCriterionType == SMESH::FT_BadOrientedVolume) || aCriterionType == SMESH::FT_LinearOrQuadratic || aCriterionType == SMESH::FT_GroupColor || - aCriterionType == SMESH::FT_ElemGeomType) + aCriterionType == SMESH::FT_ElemGeomType || + aCriterionType == SMESH::FT_CoplanarFaces + ) { bool isSignalsBlocked = aTable->signalsBlocked(); aTable->blockSignals( true ); @@ -1426,7 +1536,8 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int col, con aCompareItem->clear(); aTable->setEditable(false, row, 1); aTable->setEditable(aCriterionType == SMESH::FT_GroupColor || - aCriterionType == SMESH::FT_ElemGeomType, row, 2); + aCriterionType == SMESH::FT_ElemGeomType || + aCriterionType == SMESH::FT_CoplanarFaces, row, 2); aTable->blockSignals( isSignalsBlocked ); } else if (aCriterionType == SMESH::FT_RangeOfIds || @@ -1686,6 +1797,7 @@ const QMap& SMESHGUI_FilterTable::getCriteria (const int theType) aCriteria[ SMESH::FT_Taper ] = tr("TAPER"); aCriteria[ SMESH::FT_Skew ] = tr("SKEW"); aCriteria[ SMESH::FT_Area ] = tr("AREA"); + aCriteria[ SMESH::FT_MaxElementLength2D ] = tr("MAX_ELEMENT_LENGTH_2D"); aCriteria[ SMESH::FT_FreeEdges ] = tr("FREE_EDGES"); aCriteria[ SMESH::FT_RangeOfIds ] = tr("RANGE_OF_IDS"); aCriteria[ SMESH::FT_BelongToGeom ] = tr("BELONG_TO_GEOM"); @@ -1699,6 +1811,7 @@ const QMap& SMESHGUI_FilterTable::getCriteria (const int theType) aCriteria[ SMESH::FT_LinearOrQuadratic ] = tr("LINEAR"); aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); aCriteria[ SMESH::FT_ElemGeomType ] = tr("GEOM_TYPE"); + aCriteria[ SMESH::FT_CoplanarFaces ] = tr("COPLANAR_FACES"); } return aCriteria; } @@ -1707,14 +1820,15 @@ const QMap& SMESHGUI_FilterTable::getCriteria (const int theType) static QMap aCriteria; if (aCriteria.isEmpty()) { - aCriteria[ SMESH::FT_AspectRatio3D ] = tr("ASPECT_RATIO_3D"); - aCriteria[ SMESH::FT_RangeOfIds ] = tr("RANGE_OF_IDS"); - aCriteria[ SMESH::FT_BelongToGeom ] = tr("BELONG_TO_GEOM"); - aCriteria[ SMESH::FT_LyingOnGeom ] = tr("LYING_ON_GEOM"); - aCriteria[ SMESH::FT_BadOrientedVolume ] = tr("BAD_ORIENTED_VOLUME"); - aCriteria[ SMESH::FT_Volume3D ] = tr("VOLUME_3D"); - aCriteria[ SMESH::FT_LinearOrQuadratic ] = tr("LINEAR"); - aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); + aCriteria[ SMESH::FT_AspectRatio3D ] = tr("ASPECT_RATIO_3D"); + aCriteria[ SMESH::FT_RangeOfIds ] = tr("RANGE_OF_IDS"); + aCriteria[ SMESH::FT_BelongToGeom ] = tr("BELONG_TO_GEOM"); + aCriteria[ SMESH::FT_LyingOnGeom ] = tr("LYING_ON_GEOM"); + aCriteria[ SMESH::FT_BadOrientedVolume ] = tr("BAD_ORIENTED_VOLUME"); + aCriteria[ SMESH::FT_Volume3D ] = tr("VOLUME_3D"); + aCriteria[ SMESH::FT_MaxElementLength3D ] = tr("MAX_ELEMENT_LENGTH_3D"); + aCriteria[ SMESH::FT_LinearOrQuadratic ] = tr("LINEAR"); + aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); aCriteria[ SMESH::FT_ElemGeomType ] = tr("GEOM_TYPE"); } return aCriteria; @@ -2026,8 +2140,8 @@ bool SMESHGUI_FilterTable::GetThreshold (const int theRow, // Purpose : Set text and internal value in cell of ID value //======================================================================= void SMESHGUI_FilterTable::SetID( const int theRow, - const QString& theText, - const int theEntityType ) + const QString& theText, + const int theEntityType ) { Table* aTable = myTables[ theEntityType == -1 ? GetType() : theEntityType ]; aTable->item( theRow, 5 )->setText( theText ); @@ -2548,7 +2662,8 @@ bool SMESHGUI_FilterDlg::isValid() const aType == SMESH::FT_BelongToPlane || aType == SMESH::FT_BelongToCylinder || aType == SMESH::FT_BelongToGenSurface || - aType == SMESH::FT_LyingOnGeom) { + aType == SMESH::FT_LyingOnGeom) + { QString aName; myTable->GetThreshold(i, aName); @@ -2597,6 +2712,29 @@ bool SMESHGUI_FilterDlg::isValid() const } } } + else if (aType == SMESH::FT_CoplanarFaces) + { + QString faceID; + myTable->GetThreshold(i, faceID); + if ( faceID.isEmpty() ) + { + SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INSUFFICIENT_DATA"), + tr("FACE_ID_NOT_SELECTED")); + return false; + } + if ( myMesh->_is_nil() ) + { + SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INSUFFICIENT_DATA"), + tr("MESH_IS_NOT_SELECTED")); + return false; + } + if ( myMesh->GetElementType( faceID.toLong(), /*iselem=*/true) != SMESH::FACE ) + { + SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INSUFFICIENT_DATA"), + tr("NOT_FACE_ID").arg(faceID)); + return false; + } + } } return true; @@ -2615,7 +2753,7 @@ void SMESHGUI_FilterDlg::SetSourceWg (QWidget* theWg, } //======================================================================= -// name : SMESHGUI_FilterDlg::SetGroupIds +// name : SMESHGUI_FilterDlg::SetMesh // Purpose : Set mesh //======================================================================= void SMESHGUI_FilterDlg::SetMesh (SMESH::SMESH_Mesh_var theMesh) @@ -2976,20 +3114,31 @@ void SMESHGUI_FilterDlg::onSelectionDone() QList types; types << SMESH::FT_BelongToGeom << SMESH::FT_BelongToPlane - << SMESH::FT_BelongToCylinder << SMESH::FT_BelongToGenSurface - << SMESH::FT_LyingOnGeom; + << SMESH::FT_BelongToCylinder << SMESH::FT_BelongToGenSurface + << SMESH::FT_LyingOnGeom << SMESH::FT_CoplanarFaces; if (aList.Extent() != 1 || !myTable->CurrentCell(aRow, aCol) || !types.contains(myTable->GetCriterionType(aRow))) return; - Handle(SALOME_InteractiveObject) anIO = aList.First(); - GEOM::GEOM_Object_var anObj = SMESH::IObjectToInterface(anIO); - if (!anObj->_is_nil()) + if ( myTable->GetCriterionType(aRow) == SMESH::FT_CoplanarFaces ) + { + QString aString; + int nbElems = SMESH::GetNameOfSelectedElements(mySelector,//myViewWindow->GetSelector(), + aList.First(), aString); + if (nbElems == 1) + myTable->SetThreshold(aRow, aString); + } + else + { + Handle(SALOME_InteractiveObject) anIO = aList.First(); + GEOM::GEOM_Object_var anObj = SMESH::IObjectToInterface(anIO); + if (!anObj->_is_nil()) { myTable->SetThreshold(aRow, GEOMBase::GetName(anObj)); //myTable->SetID( aRow, GEOMBase::GetIORFromObject(anObj)); myTable->SetID(aRow, anIO->getEntry()); } + } } @@ -3020,9 +3169,9 @@ void SMESHGUI_FilterDlg::updateSelection() if (mySelectionMgr == 0) return; - TColStd_MapOfInteger allTypes; - for( int i=0; i<10; i++ ) - allTypes.Add( i ); +// TColStd_MapOfInteger allTypes; +// for( int i=0; i<10; i++ ) +// allTypes.Add( i ); SalomeApp_Study* aStudy = dynamic_cast( mySMESHGUI->application()->activeStudy() ); if( !aStudy ) return; @@ -3038,8 +3187,8 @@ void SMESHGUI_FilterDlg::updateSelection() aCriterionType == SMESH::FT_BelongToPlane || aCriterionType == SMESH::FT_BelongToCylinder || aCriterionType == SMESH::FT_BelongToGenSurface || - aCriterionType == SMESH::FT_LyingOnGeom)) { - + aCriterionType == SMESH::FT_LyingOnGeom)) + { if (aCriterionType == SMESH::FT_BelongToGeom || aCriterionType == SMESH::FT_BelongToGenSurface || aCriterionType == SMESH::FT_LyingOnGeom) { @@ -3054,9 +3203,12 @@ void SMESHGUI_FilterDlg::updateSelection() } myIsSelectionChanged = true; - } else { + } + else + { if (myIsSelectionChanged) { - mySelectionMgr->installFilter( new GEOM_TypeFilter( aStudy, -1 ) ); // This filter deactivates selection + // mySelectionMgr->installFilter( new GEOM_TypeFilter( aStudy, -1 ) ); // This filter deactivates selection + // Impossible to select any object in the OB on the second opening of FilterDlg } } } diff --git a/src/SMESHGUI/SMESHGUI_FilterDlg.h b/src/SMESHGUI/SMESHGUI_FilterDlg.h index f94a0ed3e..17f0622fa 100755 --- a/src/SMESHGUI/SMESHGUI_FilterDlg.h +++ b/src/SMESHGUI/SMESHGUI_FilterDlg.h @@ -168,6 +168,7 @@ private: void updateBtnState(); void removeAdditionalWidget( QTableWidget*, const int ); void updateAdditionalWidget(); + const char* getPrecision( const int ); const QMap& getSupportedTypes() const; diff --git a/src/SMESHGUI/SMESHGUI_FindElemByPointDlg.cxx b/src/SMESHGUI/SMESHGUI_FindElemByPointDlg.cxx index f629fba64..a0888e3ff 100644 --- a/src/SMESHGUI/SMESHGUI_FindElemByPointDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_FindElemByPointDlg.cxx @@ -79,7 +79,7 @@ SMESHGUI_FindElemByPointDlg::SMESHGUI_FindElemByPointDlg() setWindowTitle(tr("CAPTION")); QVBoxLayout* aDlgLay = new QVBoxLayout (mainFrame()); - aDlgLay->setMargin(MARGIN);; + aDlgLay->setMargin(0); aDlgLay->setSpacing(SPACING); QWidget* aMainFrame = createMainFrame (mainFrame()); @@ -164,6 +164,8 @@ QWidget* SMESHGUI_FindElemByPointDlg::createMainFrame (QWidget* theParent) QVBoxLayout* aLay = new QVBoxLayout(aFrame); + aLay->setMargin( 0 ); + aLay->setSpacing( SPACING ); aLay->addWidget(aMeshGrp); aLay->addWidget(aCoordGrp); aLay->addWidget(elementGrp); diff --git a/src/SMESHGUI/SMESHGUI_GroupDlg.cxx b/src/SMESHGUI/SMESHGUI_GroupDlg.cxx index 28461ee4f..1aab1f908 100644 --- a/src/SMESHGUI/SMESHGUI_GroupDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_GroupDlg.cxx @@ -99,6 +99,19 @@ #define SPACING 6 #define MARGIN 11 +enum grpSelectionMode { + grpNoSelection = -1, + grpNodeSelection = 0, + grpEdgeSelection = 1, + grpFaceSelection = 2, + grpVolumeSelection = 3, + grpSubMeshSelection = 4, + grpGroupSelection = 5, + grpMeshSelection = 6, + grpGeomSelection = 7, + grpAllSelection = 8, +}; + //================================================================================= // function : SMESHGUI_GroupDlg() // purpose : @@ -147,7 +160,7 @@ SMESHGUI_GroupDlg::SMESHGUI_GroupDlg( SMESHGUI* theModule, mySelectGroup->setEnabled( false ); myCurrentLineEdit = myMeshGroupLine; - setSelectionMode( 5 ); + setSelectionMode( grpGroupSelection ); } } @@ -241,59 +254,62 @@ void SMESHGUI_GroupDlg::initDialog( bool create) aContentBoxLayout->setMargin( MARGIN ); aContentBoxLayout->setSpacing( SPACING ); - QLabel* aLabel = new QLabel( tr( "SMESH_ID_ELEMENTS" ), aContentBox ); + mySelectAll = new QCheckBox( tr( "SELECT_ALL" ), aContentBox ); + + myElementsLab = new QLabel( tr( "SMESH_ID_ELEMENTS" ), aContentBox ); myElements = new QListWidget( aContentBox ); myElements->setSelectionMode( QListWidget::ExtendedSelection ); myFilter = new QPushButton( tr( "SMESH_BUT_FILTER" ), aContentBox ); - QPushButton* aAddBtn = new QPushButton( tr( "SMESH_BUT_ADD" ), aContentBox ); - QPushButton* aRemoveBtn = new QPushButton( tr( "SMESH_BUT_REMOVE" ), aContentBox ); - QPushButton* aSortBtn = new QPushButton( tr( "SMESH_BUT_SORT" ), aContentBox ); - - aContentBoxLayout->addWidget( aLabel, 0, 0 ); - aContentBoxLayout->addWidget( myElements, 1, 0, 6, 1 ); - aContentBoxLayout->addWidget( myFilter, 1, 1 ); - aContentBoxLayout->addWidget( aAddBtn, 3, 1 ); - aContentBoxLayout->addWidget( aRemoveBtn, 4, 1 ); - aContentBoxLayout->addWidget( aSortBtn, 6, 1 ); + myAddBtn = new QPushButton( tr( "SMESH_BUT_ADD" ), aContentBox ); + myRemoveBtn = new QPushButton( tr( "SMESH_BUT_REMOVE" ), aContentBox ); + mySortBtn = new QPushButton( tr( "SMESH_BUT_SORT" ), aContentBox ); + + aContentBoxLayout->addWidget( mySelectAll, 0, 0 ); + aContentBoxLayout->addWidget( myElementsLab, 1, 0 ); + aContentBoxLayout->addWidget( myElements, 2, 0, 6, 1 ); + aContentBoxLayout->addWidget( myFilter, 2, 1 ); + aContentBoxLayout->addWidget( myAddBtn, 4, 1 ); + aContentBoxLayout->addWidget( myRemoveBtn, 5, 1 ); + aContentBoxLayout->addWidget( mySortBtn, 7, 1 ); aContentBoxLayout->setColumnStretch( 0, 1 ); - aContentBoxLayout->setRowStretch( 2, 1 ); - aContentBoxLayout->setRowStretch( 5, 1 ); + aContentBoxLayout->setRowStretch( 3, 1 ); + aContentBoxLayout->setRowStretch( 6, 1 ); /***************************************************************/ - QGroupBox* aSelectBox = new QGroupBox( tr( "SMESH_SELECT_FROM" ), wg1 ); - QGridLayout* aSelectBoxLayout = new QGridLayout( aSelectBox ); - aSelectBoxLayout->setMargin( MARGIN ); - aSelectBoxLayout->setSpacing( SPACING ); + mySelectBox = new QGroupBox( tr( "SMESH_SELECT_FROM" ), wg1 ); + QGridLayout* mySelectBoxLayout = new QGridLayout( mySelectBox ); + mySelectBoxLayout->setMargin( MARGIN ); + mySelectBoxLayout->setSpacing( SPACING ); - mySelectSubMesh = new QCheckBox( tr( "SMESH_SUBMESH" ), aSelectBox ); - mySubMeshBtn = new QPushButton( aSelectBox ); + mySelectSubMesh = new QCheckBox( tr( "SMESH_SUBMESH" ), mySelectBox ); + mySubMeshBtn = new QPushButton( mySelectBox ); mySubMeshBtn->setIcon( image0 ); - mySubMeshLine = new QLineEdit( aSelectBox ); + mySubMeshLine = new QLineEdit( mySelectBox ); mySubMeshLine->setReadOnly( true ); onSelectSubMesh( false ); - mySelectGroup = new QCheckBox( tr( "SMESH_GROUP" ), aSelectBox ); - myGroupBtn = new QPushButton( aSelectBox ); + mySelectGroup = new QCheckBox( tr( "SMESH_GROUP" ), mySelectBox ); + myGroupBtn = new QPushButton( mySelectBox ); myGroupBtn->setIcon( image0 ); - myGroupLine = new QLineEdit( aSelectBox ); + myGroupLine = new QLineEdit( mySelectBox ); myGroupLine->setReadOnly( true ); onSelectGroup( false ); - aSelectBoxLayout->addWidget( mySelectSubMesh, 0, 0 ); - aSelectBoxLayout->addWidget( mySubMeshBtn, 0, 1 ); - aSelectBoxLayout->addWidget( mySubMeshLine, 0, 2 ); - aSelectBoxLayout->addWidget( mySelectGroup, 1, 0 ); - aSelectBoxLayout->addWidget( myGroupBtn, 1, 1 ); - aSelectBoxLayout->addWidget( myGroupLine, 1, 2 ); + mySelectBoxLayout->addWidget( mySelectSubMesh, 0, 0 ); + mySelectBoxLayout->addWidget( mySubMeshBtn, 0, 1 ); + mySelectBoxLayout->addWidget( mySubMeshLine, 0, 2 ); + mySelectBoxLayout->addWidget( mySelectGroup, 1, 0 ); + mySelectBoxLayout->addWidget( myGroupBtn, 1, 1 ); + mySelectBoxLayout->addWidget( myGroupLine, 1, 2 ); /***************************************************************/ QVBoxLayout* wg1Layout = new QVBoxLayout( wg1 ); wg1Layout->setMargin( 0 ); wg1Layout->setSpacing( SPACING ); wg1Layout->addWidget( aContentBox ); - wg1Layout->addWidget( aSelectBox ); + wg1Layout->addWidget( mySelectBox ); wg1Layout->setStretchFactor( aContentBox, 10 ); /***************************************************************/ @@ -374,36 +390,37 @@ void SMESHGUI_GroupDlg::initDialog( bool create) aMainLayout->addWidget(aButtons, 6, 0, 1, 3); /* signals and slots connections */ - connect(myMeshGroupBtn, SIGNAL(clicked()), this, SLOT(setCurrentSelection())); - connect(myGrpTypeGroup, SIGNAL(buttonClicked(int)), this, SLOT(onGrpTypeChanged(int))); - connect(myTypeGroup, SIGNAL(buttonClicked(int)), this, SLOT(onTypeChanged(int))); + connect(myMeshGroupBtn, SIGNAL(clicked()), this, SLOT(setCurrentSelection())); + connect(myGrpTypeGroup, SIGNAL(buttonClicked(int)), this, SLOT(onGrpTypeChanged(int))); + connect(myTypeGroup, SIGNAL(buttonClicked(int)), this, SLOT(onTypeChanged(int))); - connect(myName, SIGNAL(textChanged(const QString&)), this, SLOT(onNameChanged(const QString&))); - connect(myElements, SIGNAL(itemSelectionChanged()), this, SLOT(onListSelectionChanged())); + connect(myName, SIGNAL(textChanged(const QString&)), this, SLOT(onNameChanged(const QString&))); + connect(myElements, SIGNAL(itemSelectionChanged()), this, SLOT(onListSelectionChanged())); - connect(myFilter, SIGNAL(clicked()), this, SLOT(setFilters())); - connect(aAddBtn, SIGNAL(clicked()), this, SLOT(onAdd())); - connect(aRemoveBtn, SIGNAL(clicked()), this, SLOT(onRemove())); - connect(aSortBtn, SIGNAL(clicked()), this, SLOT(onSort())); + connect(myFilter, SIGNAL(clicked()), this, SLOT(setFilters())); + connect(mySelectAll, SIGNAL(toggled(bool)), this, SLOT(onSelectAll())); + connect(myAddBtn, SIGNAL(clicked()), this, SLOT(onAdd())); + connect(myRemoveBtn, SIGNAL(clicked()), this, SLOT(onRemove())); + connect(mySortBtn, SIGNAL(clicked()), this, SLOT(onSort())); connect(mySelectSubMesh, SIGNAL(toggled(bool)), this, SLOT(onSelectSubMesh(bool))); connect(mySelectGroup, SIGNAL(toggled(bool)), this, SLOT(onSelectGroup(bool))); - connect(mySubMeshBtn, SIGNAL(clicked()), this, SLOT(setCurrentSelection())); - connect(myGroupBtn, SIGNAL(clicked()), this, SLOT(setCurrentSelection())); + connect(mySubMeshBtn, SIGNAL(clicked()), this, SLOT(setCurrentSelection())); + connect(myGroupBtn, SIGNAL(clicked()), this, SLOT(setCurrentSelection())); connect(myGeomGroupBtn, SIGNAL(toggled(bool)), this, SLOT(onGeomSelectionButton(bool))); - connect(myColorBtn, SIGNAL(changed( QColor )), this, SLOT(onColorChanged( QColor ))); + connect(myColorBtn, SIGNAL(changed( QColor )), this, SLOT(onColorChanged( QColor ))); - connect(myOKBtn, SIGNAL(clicked()), this, SLOT(onOK())); - connect(myApplyBtn, SIGNAL(clicked()), this, SLOT(onApply())); - connect(myCloseBtn, SIGNAL(clicked()), this, SLOT(onClose())); - connect(myHelpBtn, SIGNAL(clicked()), this, SLOT(onHelp())); + connect(myOKBtn, SIGNAL(clicked()), this, SLOT(onOK())); + connect(myApplyBtn, SIGNAL(clicked()), this, SLOT(onApply())); + connect(myCloseBtn, SIGNAL(clicked()), this, SLOT(onClose())); + connect(myHelpBtn, SIGNAL(clicked()), this, SLOT(onHelp())); /* Init selection */ mySMESHGUI->SetActiveDialogBox(this); mySMESHGUI->SetState(800); - mySelectionMode = -1; + mySelectionMode = grpNoSelection; myMeshFilter = new SMESH_TypeFilter(MESH); mySubMeshFilter = new SMESH_TypeFilter(SUBMESH); myGroupFilter = new SMESH_TypeFilter(GROUP); @@ -612,7 +629,7 @@ void SMESHGUI_GroupDlg::updateButtons() bool enable = !myName->text().trimmed().isEmpty(); if (myGrpTypeId == 0) { - enable = enable && myElements->count() > 0; + enable = enable && (mySelectAll->isChecked() || myElements->count() > 0); enable = enable && (!myGroup->_is_nil() || !myMesh->_is_nil()); } else if (myGrpTypeId == 1) { @@ -620,7 +637,7 @@ void SMESHGUI_GroupDlg::updateButtons() enable = enable && myGeomObjects->length() > 0 && !myMesh->_is_nil(); } } - + myOKBtn->setEnabled(enable); myApplyBtn->setEnabled(enable); } @@ -685,6 +702,8 @@ void SMESHGUI_GroupDlg::setSelectionMode (int theMode) // PAL7314 if (myMesh->_is_nil()) return; + SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ); + bool isSelectAll = mySelectAll->isChecked(); if (mySelectionMode != theMode) { // [PAL10408] mySelectionMgr->clearSelected(); mySelectionMgr->clearFilters(); @@ -693,46 +712,51 @@ void SMESHGUI_GroupDlg::setSelectionMode (int theMode) while ( it.hasNext() ) it.next()->SetPointRepresentation(false); } - else + else { SMESH::SetPointRepresentation(false); - if (theMode < 4) { - switch (theMode) { - case 0: - if (myActorsList.count() > 0) { - QListIterator it( myActorsList ); - while ( it.hasNext() ) - it.next()->SetPointRepresentation(true); - } - else - SMESH::SetPointRepresentation(true); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(NodeSelection); - break; - case 1: - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(EdgeSelection); - break; - case 2: - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(FaceSelection); - break; - default: - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(VolumeSelection); + } + switch (theMode) { + case grpNodeSelection: + if (myActorsList.count() > 0) { + QListIterator it( myActorsList ); + while ( it.hasNext() ) + it.next()->SetPointRepresentation(true); } - } else { - if (theMode == 4) - mySelectionMgr->installFilter(mySubMeshFilter); - else if (theMode == 5) - mySelectionMgr->installFilter(myGroupFilter); - else if (theMode == 6) - mySelectionMgr->installFilter(myMeshFilter); - else if (theMode == 7) - mySelectionMgr->installFilter(myGeomFilter); - - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(ActorSelection); + else { + SMESH::SetPointRepresentation(true); + } + if ( aViewWindow ) aViewWindow->SetSelectionMode(isSelectAll ? ActorSelection : NodeSelection); + break; + case grpEdgeSelection: + if ( aViewWindow ) aViewWindow->SetSelectionMode(isSelectAll ? ActorSelection : EdgeSelection); + break; + case grpFaceSelection: + if ( aViewWindow ) aViewWindow->SetSelectionMode(isSelectAll ? ActorSelection : FaceSelection); + break; + case grpVolumeSelection: + if ( aViewWindow ) aViewWindow->SetSelectionMode(isSelectAll ? ActorSelection : VolumeSelection); + break; + case grpSubMeshSelection: + mySelectionMgr->installFilter(mySubMeshFilter); + if ( aViewWindow ) aViewWindow->SetSelectionMode(ActorSelection); + break; + case grpGroupSelection: + mySelectionMgr->installFilter(myGroupFilter); + if ( aViewWindow ) aViewWindow->SetSelectionMode(ActorSelection); + break; + case grpMeshSelection: + mySelectionMgr->installFilter(myMeshFilter); + if ( aViewWindow ) aViewWindow->SetSelectionMode(ActorSelection); + break; + case grpGeomSelection: + mySelectionMgr->installFilter(myGeomFilter); + if ( aViewWindow ) aViewWindow->SetSelectionMode(ActorSelection); + break; + default: + if ( aViewWindow ) aViewWindow->SetSelectionMode(ActorSelection); + break; } + if ( aViewWindow ) aViewWindow->Repaint(); mySelectionMode = theMode; } } @@ -750,7 +774,7 @@ bool SMESHGUI_GroupDlg::onApply() return false; if (myGrpTypeId == 0) { // on mesh elements - if (!myElements->count()) + if (!mySelectAll->isChecked() && !myElements->count()) return false; mySelectionMgr->clearSelected(); @@ -778,15 +802,23 @@ bool SMESHGUI_GroupDlg::onApply() case 3: aType = SMESH::VOLUME; break; } - SMESH::long_array_var anIdList = new SMESH::long_array; - int i, k = myElements->count(); - anIdList->length(k); - for (i = 0; i < k; i++) { - anIdList[i] = myElements->item(i)->text().toInt(); - } - myGroup = SMESH::AddGroup(myMesh, aType, myName->text()); - myGroup->Add(anIdList.inout()); + + if ( mySelectAll->isChecked() ) { + // select all + myGroup->AddFrom(myMesh.in()); + } + else { + // select manually + SMESH::long_array_var anIdList = new SMESH::long_array; + int i, k = myElements->count(); + anIdList->length(k); + for (i = 0; i < k; i++) { + anIdList[i] = myElements->item(i)->text().toInt(); + } + + myGroup->Add(anIdList.inout()); + } SALOMEDS::Color aColor = getGroupColor(); myGroup->SetColor(aColor); @@ -818,37 +850,44 @@ bool SMESHGUI_GroupDlg::onApply() } } - QList aAddList; - - int i, total = myElements->count(); - for (i = 0; i < total; i++) { - int anId = myElements->item(i)->text().toInt(); - int idx = myIdList.indexOf(anId); - if ( idx == -1 ) - aAddList.append(anId); - else - myIdList.removeAt(idx); - } - if (!aAddList.empty()) { - SMESH::long_array_var anIdList = new SMESH::long_array; - int added = aAddList.count(); - anIdList->length(added); - for (i = 0; i < added; i++) - anIdList[i] = aAddList[i]; - myGroup->Add(anIdList.inout()); + if ( mySelectAll->isChecked() ) { + // select all + myGroup->Clear(); + myGroup->AddFrom(myMesh.in()); } - if (!myIdList.empty()) { - SMESH::long_array_var anIdList = new SMESH::long_array; - int removed = myIdList.count(); - anIdList->length(removed); - for (i = 0; i < removed; i++) - anIdList[i] = myIdList[i]; - myGroup->Remove(anIdList.inout()); - } - /* init for next operation */ - myIdList.clear(); - for (i = 0; i < total; i++) { - myIdList.append(myElements->item(i)->text().toInt()); + else { + QList aAddList; + + int i, total = myElements->count(); + for (i = 0; i < total; i++) { + int anId = myElements->item(i)->text().toInt(); + int idx = myIdList.indexOf(anId); + if ( idx == -1 ) + aAddList.append(anId); + else + myIdList.removeAt(idx); + } + if (!aAddList.empty()) { + SMESH::long_array_var anIdList = new SMESH::long_array; + int added = aAddList.count(); + anIdList->length(added); + for (i = 0; i < added; i++) + anIdList[i] = aAddList[i]; + myGroup->Add(anIdList.inout()); + } + if (!myIdList.empty()) { + SMESH::long_array_var anIdList = new SMESH::long_array; + int removed = myIdList.count(); + anIdList->length(removed); + for (i = 0; i < removed; i++) + anIdList[i] = myIdList[i]; + myGroup->Remove(anIdList.inout()); + } + /* init for next operation */ + myIdList.clear(); + for (i = 0; i < total; i++) { + myIdList.append(myElements->item(i)->text().toInt()); + } } } @@ -1336,6 +1375,24 @@ void SMESHGUI_GroupDlg::onObjectSelectionChanged() myIsBusy = false; } +//================================================================================= +// function : onSelectSubMesh() +// purpose : Called when selection in 3D view or ObjectBrowser is changed +//================================================================================= +void SMESHGUI_GroupDlg::onSelectAll() +{ + myElementsLab->setEnabled( !mySelectAll->isChecked() ); + myElements->setEnabled( !mySelectAll->isChecked() ); + myFilter->setEnabled( !mySelectAll->isChecked() ); + myAddBtn->setEnabled( !mySelectAll->isChecked() ); + myRemoveBtn->setEnabled( !mySelectAll->isChecked() ); + mySortBtn->setEnabled( !mySelectAll->isChecked() ); + mySelectBox->setEnabled( !mySelectAll->isChecked() ); + int selMode = mySelectionMode; + mySelectionMode = grpNoSelection; + setSelectionMode( selMode ); +} + //================================================================================= // function : onSelectSubMesh() // purpose : Called when selection in 3D view or ObjectBrowser is changed @@ -1350,7 +1407,7 @@ void SMESHGUI_GroupDlg::onSelectSubMesh(bool on) //VSR: mySelectGeomGroup->setChecked(false); //VSR: } myCurrentLineEdit = mySubMeshLine; - setSelectionMode(4); + setSelectionMode(grpSubMeshSelection); } else { mySubMeshLine->setText( "" ); @@ -1374,7 +1431,7 @@ void SMESHGUI_GroupDlg::onSelectGroup(bool on) mySelectSubMesh->setChecked(false); } myCurrentLineEdit = myGroupLine; - setSelectionMode(5); + setSelectionMode(grpGroupSelection); } else { myGroupLine->setText( "" ); @@ -1402,7 +1459,7 @@ void SMESHGUI_GroupDlg::onSelectGeomGroup(bool on) } myCurrentLineEdit = myGeomGroupLine; updateGeomPopup(); - setSelectionMode(8); + setSelectionMode(grpAllSelection); } else { myGeomGroupBtn->setChecked(false); @@ -1427,9 +1484,9 @@ void SMESHGUI_GroupDlg::setCurrentSelection() disconnect(myMeshGroupBtn, SIGNAL(clicked()), this, SLOT(setCurrentSelection())); mySelectionMgr->clearSelected(); if (myCreate) - setSelectionMode(6); + setSelectionMode(grpMeshSelection); else - setSelectionMode(5); + setSelectionMode(grpGroupSelection); connect(myMeshGroupBtn, SIGNAL(clicked()), this, SLOT(setCurrentSelection())); myCurrentLineEdit = myMeshGroupLine; onObjectSelectionChanged(); @@ -1960,7 +2017,7 @@ void SMESHGUI_GroupDlg::enterEvent (QEvent*) if (!isEnabled()) { mySMESHGUI->EmitSignalDeactivateDialog(); setEnabled(true); - mySelectionMode = -1; + mySelectionMode = grpNoSelection; setSelectionMode(myTypeId); //mySMESHGUI->SetActiveDialogBox((QDialog*)this); mySMESHGUI->SetActiveDialogBox(this); @@ -2038,12 +2095,12 @@ void SMESHGUI_GroupDlg::onGeomSelectionButton(bool isBtnOn) myCurrentLineEdit = myGeomGroupLine; QAction* a = myGeomPopup->exec( QCursor::pos() ); if (!a || myActions[a] == DIRECT_GEOM_INDEX) - setSelectionMode(7); + setSelectionMode(grpGeomSelection); } else if (!isBtnOn) { myCurrentLineEdit = 0; - setSelectionMode(8); + setSelectionMode(grpAllSelection); } } @@ -2056,7 +2113,7 @@ void SMESHGUI_GroupDlg::onGeomPopup( QAction* a ) int index = myActions[a]; if ( index == GEOM_BY_MESH_INDEX ) { - mySelectionMode = -1; + mySelectionMode = grpNoSelection; if ( !myShapeByMeshOp ) { myShapeByMeshOp = new SMESHGUI_ShapeByMeshOp(true); connect(myShapeByMeshOp, SIGNAL(committed(SUIT_Operation*)), @@ -2117,7 +2174,7 @@ void SMESHGUI_GroupDlg::onCloseShapeByMeshDlg(SUIT_Operation* op) if ( myShapeByMeshOp == op ) { show(); - setSelectionMode(7); + setSelectionMode(grpGeomSelection); } } diff --git a/src/SMESHGUI/SMESHGUI_GroupDlg.h b/src/SMESHGUI/SMESHGUI_GroupDlg.h index 31c93d812..92f749110 100644 --- a/src/SMESHGUI/SMESHGUI_GroupDlg.h +++ b/src/SMESHGUI/SMESHGUI_GroupDlg.h @@ -40,6 +40,8 @@ #include CORBA_SERVER_HEADER(SMESH_Mesh) #include CORBA_SERVER_HEADER(SMESH_Group) +class QGroupBox; +class QLabel; class QLineEdit; class QButtonGroup; class QListWidget; @@ -96,6 +98,7 @@ private slots: void onListSelectionChanged(); void onObjectSelectionChanged(); + void onSelectAll(); void onSelectSubMesh( bool ); void onSelectGroup( bool ); void onSelectGeomGroup( bool ); @@ -157,13 +160,18 @@ private: QButtonGroup* myGrpTypeGroup; QStackedWidget* myWGStack; + QCheckBox* mySelectAll; + QLabel* myElementsLab; QListWidget* myElements; QPushButton* myFilter; + QPushButton* myAddBtn; + QPushButton* myRemoveBtn; + QPushButton* mySortBtn; + QGroupBox* mySelectBox; QCheckBox* mySelectSubMesh; QPushButton* mySubMeshBtn; QLineEdit* mySubMeshLine; - QCheckBox* mySelectGroup; QPushButton* myGroupBtn; QLineEdit* myGroupLine; diff --git a/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx b/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx index 9fefa98da..581aa5326 100644 --- a/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx @@ -301,7 +301,7 @@ bool SMESHGUI_GroupOnShapeOp::onApply() if ( !aStudy ) return false; // mesh - _PTR(SObject) meshSO = aStudy->FindObjectID( myMeshID.toLatin1().data() ); + _PTR(SObject) meshSO = aStudy->FindObjectID( myMeshID.toLatin1().data() ); SMESH::SMESH_Mesh_var mesh = SMESH::SObjectToInterface( meshSO ); if ( mesh->_is_nil() ) return false; @@ -352,7 +352,15 @@ bool SMESHGUI_GroupOnShapeOp::onApply() update( UF_ObjBrowser | UF_Model ); - init(); + // Re-init controls to create the next group + myElemGeoIDs.clear(); + myNodeGeoIDs.clear(); + removeCustomFilters(); + myDlg->myNodeGeomList->clear(); + myDlg->myElemGeomList->clear(); + myDlg->myElemGeomBtn->setChecked(false); + myDlg->myNodeGeomBtn->setChecked(false); + myDlg->updateButtons(); return !group->_is_nil(); } diff --git a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx index b6e28773a..a964d8cfc 100644 --- a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx +++ b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx @@ -19,12 +19,11 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_Hypotheses.cxx +// Author : Julia DOROVSKIKH, Open CASCADE S.A.S. +// SMESH includes -// SMESH SMESHGUI : GUI for SMESH component -// File : SMESHGUI_Hypotheses.cxx -// Author : Julia DOROVSKIKH, Open CASCADE S.A.S. -// SMESH includes -// #include "SMESHGUI_Hypotheses.h" #include "SMESHGUI.h" @@ -53,6 +52,10 @@ #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 ) { @@ -86,14 +89,22 @@ void SMESHGUI_GenericHypothesisCreator::create( bool isAlgo, myIsCreate = true; // Create hypothesis/algorithm - if (isAlgo) - SMESH::CreateHypothesis( hypType(), theHypName, isAlgo ); - - else - { - SMESH::SMESH_Hypothesis_var aHypothesis = + if (isAlgo) { + SMESH::SMESH_Hypothesis_var anAlgo = + SMESH::CreateHypothesis( hypType(), theHypName, isAlgo ); +#ifdef WITHGENERICOBJ + if (!CORBA::is_nil(anAlgo)) + anAlgo->Destroy(); +#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->Destroy(); +#endif } } @@ -111,13 +122,16 @@ void SMESHGUI_GenericHypothesisCreator::edit( SMESH::SMESH_Hypothesis_ptr theHyp editHypothesis( theHypothesis, theHypName, theParent, obj, slot ); } -void SMESHGUI_GenericHypothesisCreator::editHypothesis( SMESH::SMESH_Hypothesis_ptr h, +void SMESHGUI_GenericHypothesisCreator::editHypothesis( SMESH::SMESH_Hypothesis_ptr h, const QString& theHypName, QWidget* theParent, QObject* obj, const QString& slot ) { 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 ) ) ); @@ -140,7 +154,7 @@ void SMESHGUI_GenericHypothesisCreator::editHypothesis( SMESH::SMESH_Hypothesis_ else emit finished( QDialog::Accepted ); } - + QFrame* SMESHGUI_GenericHypothesisCreator::buildStdFrame() { if( CORBA::is_nil( hypothesis() ) ) @@ -169,7 +183,7 @@ QFrame* SMESHGUI_GenericHypothesisCreator::buildStdFrame() GroupC1Layout->addWidget( lab, i, 0 ); QWidget* w = getCustomWidget( *anIt, GroupC1, i ); - if ( !w ) + if ( !w ) switch( (*anIt).myValue.type() ) { case QVariant::Int: @@ -287,6 +301,9 @@ void SMESHGUI_GenericHypothesisCreator::onDialogFinished( int result ) } } SMESHGUI::GetSMESHGUI()->updateObjBrowser( true, 0 ); +#ifdef WITHGENERICOBJ + myHypo->Destroy(); +#endif myHypo = SMESH::SMESH_Hypothesis::_nil(); myInitParamsHypo = SMESH::SMESH_Hypothesis::_nil(); @@ -316,26 +333,22 @@ bool SMESHGUI_GenericHypothesisCreator::getStdParamFromDlg( ListOfStdParams& par item.myValue = sb->value(); params.append( item ); } - else if( (*anIt)->inherits( "SalomeApp_DoubleSpinBox" ) ) { SalomeApp_DoubleSpinBox* sb = ( SalomeApp_DoubleSpinBox* )( *anIt ); item.myValue = sb->value(); params.append( item ); } - else if( (*anIt)->inherits( "QLineEdit" ) ) { QLineEdit* line = ( QLineEdit* )( *anIt ); item.myValue = line->text(); params.append( item ); } - else if ( getParamFromCustomWidget( item, *anIt )) { params.append( item ); } - else res = false; } @@ -351,7 +364,7 @@ QStringList SMESHGUI_GenericHypothesisCreator::getVariablesFromDlg() const if( (*anIt)->inherits( "QAbstractSpinBox" ) ) { QAbstractSpinBox* sb = ( QAbstractSpinBox* )( *anIt ); aResult.append(sb->text()); - } + } } return aResult; } @@ -440,7 +453,7 @@ SMESHGUI_GenericHypothesisCreator::ListOfWidgets& SMESHGUI_GenericHypothesisCrea } QtxDialog* SMESHGUI_GenericHypothesisCreator:: dlg() const -{ +{ return myDlg; } @@ -565,7 +578,7 @@ SMESHGUI_HypothesisDlg::SMESHGUI_HypothesisDlg( SMESHGUI_GenericHypothesisCreato QHBoxLayout* titLay = new QHBoxLayout( titFrame ); titLay->setMargin( 0 ); titLay->setSpacing( SPACING ); - + myIconLabel = new QLabel( titFrame ); myIconLabel->setScaledContents( false ); myIconLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); @@ -634,7 +647,7 @@ void SMESHGUI_HypothesisDlg::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)); } @@ -642,7 +655,7 @@ void SMESHGUI_HypothesisDlg::onHelp() void SMESHGUI_HypothesisDlg::setHIcon( const QPixmap& p ) { - myIconLabel->setPixmap( p ); + myIconLabel->setPixmap( p ); } void SMESHGUI_HypothesisDlg::setType( const QString& t ) @@ -672,7 +685,7 @@ HypothesisData::HypothesisData( const QString& theTypeName, IconId( theIconId ), Dim( theDim ), IsAux( theIsAux ), - NeededHypos( theNeededHypos ), + NeededHypos( theNeededHypos ), OptionalHypos( theOptionalHypos ), InputTypes( theInputTypes ), OutputTypes( theOutputTypes ), @@ -681,7 +694,7 @@ HypothesisData::HypothesisData( const QString& theTypeName, { } -HypothesesSet::HypothesesSet( const QString& theSetName ) +HypothesesSet::HypothesesSet( const QString& theSetName ) : myHypoSetName( theSetName ), myIsAlgo( false ) { @@ -690,8 +703,8 @@ HypothesesSet::HypothesesSet( const QString& theSetName ) HypothesesSet::HypothesesSet( const QString& theSetName, const QStringList& theHypoList, const QStringList& theAlgoList ) - : myHypoSetName( theSetName ), - myHypoList( theHypoList ), + : myHypoSetName( theSetName ), + myHypoList( theHypoList ), myAlgoList( theAlgoList ), myIsAlgo( false ) { @@ -747,4 +760,3 @@ QString HypothesesSet::current() const { return list()->at(myIndex); } - diff --git a/src/SMESHGUI/SMESHGUI_Make2DFrom3DOp.cxx b/src/SMESHGUI/SMESHGUI_Make2DFrom3DOp.cxx index ffbc3b80d..4ffc3f09e 100644 --- a/src/SMESHGUI/SMESHGUI_Make2DFrom3DOp.cxx +++ b/src/SMESHGUI/SMESHGUI_Make2DFrom3DOp.cxx @@ -16,235 +16,389 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // +// File : SMESHGUI_Make2DFrom3D.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) -// File : SMESHGUI_Make2DFrom3DOp.cxx -// Author : Open CASCADE S.A.S. -// SMESH includes -// #include "SMESHGUI_Make2DFrom3DOp.h" #include "SMESHGUI.h" #include "SMESHGUI_Utils.h" -#include "SMESHGUI_VTKUtils.h" #include "SMESHGUI_MeshUtils.h" -#include "SMESHGUI_MeshInfosBox.h" +#include "SMESH_TypeFilter.hxx" +#include "SMESH_LogicalFilter.hxx" // SALOME GUI includes -#include - +#include +#include +#include #include #include -#include #include -#include - -// SALOME KERNEL includes -#include -#include - -// Qt includes // IDL includes #include -#include CORBA_SERVER_HEADER(SMESH_Gen) -#include CORBA_SERVER_HEADER(SMESH_MeshEditor) +#include CORBA_SERVER_HEADER(SMESH_Group) -#include -#include -#include +// Qt includes #include -#include -#include - -// MESH includes -#include "SMDSAbs_ElementType.hxx" -#include "SMDSAbs_ElementType.hxx" - +#include +#include +#include +#include +#include #define SPACING 6 #define MARGIN 11 -// ========================================================================================= /*! - * \brief Dialog to show creted mesh statistic - */ -//======================================================================= + \class SMESHGUI_Make2DFrom3DDlg + \brief Copy Mesh dialog box +*/ SMESHGUI_Make2DFrom3DDlg::SMESHGUI_Make2DFrom3DDlg( QWidget* parent ) - : SMESHGUI_Dialog( parent, false, true, Close/* | Help*/ ) + : SMESHGUI_Dialog( parent, false, true, OK | Apply | Close | Help ) { + // title setWindowTitle( tr("CAPTION") ); - QVBoxLayout* aDlgLay = new QVBoxLayout (mainFrame()); + + // mesh + setObjectPixmap( "SMESH", tr( "ICON_SELECT" ) ); + createObject( tr( "MESH" ), mainFrame(), Mesh ); + + // mode + QGroupBox* aModeGrp = new QGroupBox( tr( "MODE" ), mainFrame() ); + QHBoxLayout* aModeGrpLayout = new QHBoxLayout( aModeGrp ); + aModeGrpLayout->setMargin( MARGIN ); + aModeGrpLayout->setSpacing( SPACING ); + my2dFrom3dRB = new QRadioButton( tr( "2D_FROM_3D" ), aModeGrp ); + my1dFrom2dRB = new QRadioButton( tr( "1D_FROM_2D" ), aModeGrp ); + my1dFrom3dRB = new QRadioButton( tr( "1D_FROM_3D" ), aModeGrp ); + aModeGrpLayout->addWidget( my2dFrom3dRB ); + aModeGrpLayout->addWidget( my1dFrom2dRB ); + aModeGrpLayout->addWidget( my1dFrom3dRB ); + + // target + QGroupBox* aTargetGrp = new QGroupBox( tr( "TARGET" ), mainFrame() ); + QGridLayout* aTargetGrpLayout = new QGridLayout( aTargetGrp ); + aTargetGrpLayout->setMargin( MARGIN ); + aTargetGrpLayout->setSpacing( SPACING ); + myThisMeshRB = new QRadioButton( tr( "THIS_MESH" ), aTargetGrp ); + myNewMeshRB = new QRadioButton( tr( "NEW_MESH" ), aTargetGrp ); + myMeshName = new QLineEdit( aTargetGrp ); + myCopyCheck = new QCheckBox( tr( "COPY_SRC" ), aTargetGrp ); + myMissingCheck = new QCheckBox( tr( "MISSING_ONLY" ), aTargetGrp ); + aTargetGrpLayout->addWidget( myThisMeshRB, 0, 0 ); + aTargetGrpLayout->addWidget( myNewMeshRB, 1, 0 ); + aTargetGrpLayout->addWidget( myMeshName, 1, 1 ); + aTargetGrpLayout->addWidget( myCopyCheck, 2, 0 ); + aTargetGrpLayout->addWidget( myMissingCheck, 2, 1 ); + myGroupCheck = new QCheckBox( tr( "CREATE_GROUP" ), mainFrame() ); + myGroupName = new QLineEdit( mainFrame() ); + + // layout + QGridLayout* aDlgLay = new QGridLayout( mainFrame() ); aDlgLay->setMargin( 0 ); aDlgLay->setSpacing( SPACING ); - QFrame* aMainFrame = createMainFrame(mainFrame()); - aDlgLay->addWidget(aMainFrame); - aDlgLay->setStretchFactor(aMainFrame, 1); + aDlgLay->addWidget( objectWg( Mesh, Label ), 0, 0 ); + aDlgLay->addWidget( objectWg( Mesh, Btn ), 0, 1 ); + aDlgLay->addWidget( objectWg( Mesh, Control ), 0, 2 ); + aDlgLay->addWidget( aModeGrp, 1, 0, 1, 3 ); + aDlgLay->addWidget( aTargetGrp, 2, 0, 1, 3 ); + aDlgLay->addWidget( myGroupCheck, 3, 0 ); + aDlgLay->addWidget( myGroupName, 3, 1, 1, 2 ); + + // connect signals + connect( myThisMeshRB, SIGNAL( clicked() ), this, SLOT( onTargetChanged() ) ); + connect( myNewMeshRB, SIGNAL( clicked() ), this, SLOT( onTargetChanged() ) ); + connect( myGroupCheck, SIGNAL( clicked() ), this, SLOT( onGroupChecked() ) ); + + // init dlg + my2dFrom3dRB->setChecked( true ); + myThisMeshRB->setChecked( true ); + myMissingCheck->setChecked( true ); + onTargetChanged(); + onGroupChecked(); } -// ========================================================================================= -/*! - * \brief Dialog destructor - */ -//======================================================================= - SMESHGUI_Make2DFrom3DDlg::~SMESHGUI_Make2DFrom3DDlg() { } -//======================================================================= -// function : createMainFrame() -// purpose : Create frame containing dialog's fields -//======================================================================= - -QFrame* SMESHGUI_Make2DFrom3DDlg::createMainFrame (QWidget* theParent) +SMESH::Bnd_Dimension SMESHGUI_Make2DFrom3DDlg::mode() const { - QFrame* aFrame = new QFrame(theParent); + if ( my2dFrom3dRB->isChecked() ) + return SMESH::BND_2DFROM3D; + else if ( my1dFrom2dRB->isChecked() ) + return SMESH::BND_1DFROM2D; + else + return SMESH::BND_1DFROM3D; +} - SUIT_ResourceMgr* rm = resourceMgr(); - QPixmap iconCompute (rm->loadPixmap("SMESH", tr("ICON_2D_FROM_3D"))); +bool SMESHGUI_Make2DFrom3DDlg::needNewMesh() const +{ + return myNewMeshRB->isChecked(); +} - // Mesh name - QGroupBox* nameBox = new QGroupBox(tr("SMESH_MESHINFO_NAME"), aFrame ); - QHBoxLayout* nameBoxLayout = new QHBoxLayout(nameBox); - nameBoxLayout->setMargin(MARGIN); nameBoxLayout->setSpacing(SPACING); - myMeshName = new QLabel(nameBox); - nameBoxLayout->addWidget(myMeshName); +QString SMESHGUI_Make2DFrom3DDlg::getNewMeshName() const +{ + return myMeshName->text().trimmed(); +} - // Mesh Info +void SMESHGUI_Make2DFrom3DDlg::setNewMeshName( const QString& name ) +{ + myMeshName->setText( name ); +} - myFullInfo = new SMESHGUI_MeshInfosBox(true, aFrame); +bool SMESHGUI_Make2DFrom3DDlg::needGroup() const +{ + return myGroupCheck->isChecked(); +} - // add all widgets to aFrame - QVBoxLayout* aLay = new QVBoxLayout(aFrame); - aLay->setMargin( 0 ); - aLay->setSpacing( 0 ); - aLay->addWidget( nameBox ); - aLay->addWidget( myFullInfo ); +QString SMESHGUI_Make2DFrom3DDlg::getGroupName() const +{ + return myGroupName->text().trimmed(); +} - ((QPushButton*) button( OK ))->setDefault( true ); - return aFrame; +void SMESHGUI_Make2DFrom3DDlg::setGroupName( const QString& name ) +{ + myGroupName->setText( name ); } -//================================================================================ -/*! - * \brief set name of the mesh -*/ -//================================================================================ +bool SMESHGUI_Make2DFrom3DDlg::copySource() const +{ + return myCopyCheck->isChecked(); +} -void SMESHGUI_Make2DFrom3DDlg::SetMeshName(const QString& theName) +bool SMESHGUI_Make2DFrom3DDlg::copyMissingOnly() const { - myMeshName->setText( theName ); + return myMissingCheck->isChecked(); } -//================================================================================ -/*! - * \brief set mesh info -*/ -//================================================================================ +void SMESHGUI_Make2DFrom3DDlg::onTargetChanged() +{ + myMeshName->setEnabled( myNewMeshRB->isChecked() ); + myCopyCheck->setEnabled( myNewMeshRB->isChecked() ); + myMissingCheck->setEnabled( myNewMeshRB->isChecked() ); +} -void SMESHGUI_Make2DFrom3DDlg::SetMeshInfo(const SMESH::long_array& theInfo) +void SMESHGUI_Make2DFrom3DDlg::onGroupChecked() { - myFullInfo->SetMeshInfo( theInfo ); + myGroupName->setEnabled( myGroupCheck->isChecked() ); } -//================================================================================ /*! - * \brief Constructor + \class SMESHGUI_Make2DFrom3DOp + \brief Copy Mesh operation class */ -//================================================================================ SMESHGUI_Make2DFrom3DOp::SMESHGUI_Make2DFrom3DOp() - : SMESHGUI_Operation() + : SMESHGUI_SelectionOp() { - myDlg = new SMESHGUI_Make2DFrom3DDlg(desktop()); } -//================================================================================ -/*! - * \brief Desctructor -*/ -//================================================================================ - SMESHGUI_Make2DFrom3DOp::~SMESHGUI_Make2DFrom3DOp() { + if ( myDlg ) + delete myDlg; } -//================================================================================ -/*! - * \brief perform it's intention action: compute 2D mesh on 3D - */ -//================================================================================ +LightApp_Dialog* SMESHGUI_Make2DFrom3DOp::dlg() const +{ + return myDlg; +} void SMESHGUI_Make2DFrom3DOp::startOperation() { - myMesh = SMESH::SMESH_Mesh::_nil(); + if( !myDlg ) + myDlg = new SMESHGUI_Make2DFrom3DDlg( desktop() ); + + mySrc = SMESH::SMESH_IDSource::_nil(); - // check selection - LightApp_SelectionMgr *Sel = selectionMgr(); - SALOME_ListIO selected; Sel->selectedObjects( selected ); + myHelpFileName = "make_2dmesh_from_3d_page.html"; - int nbSel = selected.Extent(); - if (nbSel != 1) { - SUIT_MessageBox::warning(desktop(), - tr("SMESH_WRN_WARNING"), - tr("SMESH_WRN_NO_AVAILABLE_DATA")); - onCancel(); - return; - } + SMESHGUI_SelectionOp::startOperation(); + + myDlg->activateObject( SMESHGUI_Make2DFrom3DDlg::Mesh ); + myDlg->setNewMeshName( SMESH::UniqueName( "Mesh_1" ) ); + myDlg->setGroupName( SMESH::UniqueName( "Group" ) ); + myDlg->show(); + + selectionDone(); +} - Handle(SALOME_InteractiveObject) anIO = selected.First(); - myMesh = SMESH::GetMeshByIO(anIO); - if (myMesh->_is_nil()) { - SUIT_MessageBox::warning(desktop(), - tr("SMESH_WRN_WARNING"), - tr("SMESH_WRN_NO_AVAILABLE_DATA")); - onCancel(); - return; +void SMESHGUI_Make2DFrom3DOp::selectionDone() +{ + if ( !dlg() ) return; + + if ( dlg()->isVisible() ) { + try { + QStringList names, ids; + LightApp_Dialog::TypesList types; + selected( names, types, ids ); + if ( names.count() == 1 ) + myDlg->selectObject( names, types, ids ); + else + myDlg->clearSelection(); + } + catch ( const SALOME::SALOME_Exception& S_ex ) { + SalomeApp_Tools::QtCatchCorbaException( S_ex ); + } + catch ( ... ) { + } } +} - SMESHGUI_Operation::startOperation(); +SUIT_SelectionFilter* SMESHGUI_Make2DFrom3DOp::createFilter( const int theId ) const +{ + SUIT_SelectionFilter* f = 0; + if ( theId == SMESHGUI_Make2DFrom3DDlg::Mesh ) { + QList filters; + filters.append( new SMESH_TypeFilter( MESHorSUBMESH ) ); + filters.append( new SMESH_TypeFilter( GROUP ) ); + f = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR ); + } + return f; +} +bool SMESHGUI_Make2DFrom3DOp::isValid( QString& msg ) const +{ + if ( !dlg() ) return false; + + // check if any source data is selected + QString entry = myDlg->selectedObject( SMESHGUI_Make2DFrom3DDlg::Mesh ); + SMESH::SMESH_IDSource_var obj; + _PTR(SObject) sobj = SMESHGUI::activeStudy()->studyDS()->FindObjectID( entry.toLatin1().constData() ); + if ( sobj ) + obj = SMESH::SObjectToInterface( sobj ); + + if ( obj->_is_nil() ) { + msg = tr( "SMESH_ERR_NO_INPUT_MESH" ); + return false; + } - // backup mesh info before 2D mesh computation - SMESH::long_array_var anOldInfo = myMesh->GetMeshInfo(); + // check if source contains elements of required type + SMESH::Bnd_Dimension mode = myDlg->mode(); + SMESH::array_of_ElementType_var types = obj->GetTypes(); + bool has3d = false; + bool has2d = false; + for ( int i = 0; i < types->length(); i++ ) { + if ( types[i] == SMESH::VOLUME ) has3d = true; + else if ( types[i] == SMESH::FACE ) has2d = true; + } - if (!compute2DMesh()) { - SUIT_MessageBox::warning(desktop(), - tr("SMESH_WRN_WARNING"), - tr("SMESH_WRN_COMPUTE_FAILED")); - onCancel(); - return; - } - // get new mesh statistic - SMESH::long_array_var aNewInfo = myMesh->GetMeshInfo(); - // get difference in mesh statistic from old to new - for ( int i = SMDSEntity_Node; i < SMDSEntity_Last; i++ ) - aNewInfo[i] -= anOldInfo[i]; - - // update presentation - SMESH::Update(anIO, SMESH::eDisplay); - - // show computated result - _PTR(SObject) aMeshSObj = SMESH::FindSObject(myMesh); - if ( aMeshSObj ) - myDlg->SetMeshName( aMeshSObj->GetName().c_str() ); - myDlg->SetMeshInfo( aNewInfo ); - myDlg->show(); /*exec();*/ - commit(); - SMESHGUI::Modified(); -} - -//================================================================================ -/*! - * \brief compute 2D mesh on initial 3D - */ -//================================================================================ + if ( ( mode == SMESH::BND_2DFROM3D || mode == SMESH::BND_1DFROM3D ) && !has3d ) { + msg = tr( "SMESH_ERR_NO_3D_ELEMENTS" ); + return false; + } + else if ( mode == SMESH::BND_1DFROM2D && !has2d ) { + msg = tr( "SMESH_ERR_NO_2D_ELEMENTS" ); + return false; + } + + // check if new mesh name is specified + if ( myDlg->needNewMesh() && myDlg->getNewMeshName().isEmpty() ) { + msg = tr( "SMESH_ERR_MESH_NAME_NOT_SPECIFIED" ); + return false; + } + + // check if group name is specified + if ( myDlg->needGroup() && myDlg->getGroupName().isEmpty() ) { + msg = tr( "SMESH_ERR_GRP_NAME_NOT_SPECIFIED" ); + return false; + } + + return true; +} bool SMESHGUI_Make2DFrom3DOp::compute2DMesh() { SUIT_OverrideCursor wc; - SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor(); - return aMeshEditor->Make2DMeshFrom3D(); + + bool ok = false; + try { + QString entry = myDlg->selectedObject( SMESHGUI_Make2DFrom3DDlg::Mesh ); + _PTR(SObject) sobj = SMESHGUI::activeStudy()->studyDS()->FindObjectID( entry.toLatin1().constData() ); + SMESH::SMESH_IDSource_var obj = SMESH::SObjectToInterface( sobj ); + + SMESH::Bnd_Dimension mode = myDlg->mode(); + QString meshName = myDlg->needNewMesh() ? myDlg->getNewMeshName() : QString(); + QString groupName = myDlg->needGroup() ? myDlg->getGroupName() : QString(); + bool copySrc = myDlg->copySource(); + bool copyAll = !myDlg->copyMissingOnly(); + + SMESH::SMESH_Mesh_var srcMesh = SMESH::SMESH_Mesh::_narrow( obj ); + if ( CORBA::is_nil( srcMesh ) ) { + SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_narrow( obj ); + if ( !CORBA::is_nil( subMesh ) ) + srcMesh = subMesh->GetFather(); + } + if ( CORBA::is_nil( srcMesh ) ) { + SMESH::SMESH_GroupBase_var grp = SMESH::SMESH_GroupBase::_narrow( obj ); + if ( !CORBA::is_nil( grp ) ) + srcMesh = grp->GetMesh(); + } + + if ( !CORBA::is_nil( srcMesh ) ) { + SMESH::SMESH_MeshEditor_var aMeshEditor = srcMesh->GetMeshEditor(); + SMESH::SMESH_Group_var newGrp; + SMESH::SMESH_Mesh_var mesh = aMeshEditor->MakeBoundaryMesh( obj.in(), + mode, + groupName.toLatin1().constData(), + meshName.toLatin1().constData(), + copySrc, + copyAll, + newGrp.out() ); + if ( !mesh->_is_nil() ) { +#ifdef WITHGENERICOBJ + mesh->Destroy(); +#endif + } + if ( !newGrp->_is_nil() ) { +#ifdef WITHGENERICOBJ + newGrp->Destroy(); +#endif + } + ok = true; + } + } + catch ( ... ) { + } + return ok; +} + +bool SMESHGUI_Make2DFrom3DOp::onApply() +{ + if ( isStudyLocked() ) + return false; + + QString msg; + if ( !isValid( msg ) ) { + dlg()->show(); + if ( msg != "" ) + SUIT_MessageBox::warning( myDlg, tr( "SMESH_ERROR" ), msg ); + return false; + } + + bool res = false; + try { + res = compute2DMesh(); + } + catch ( const SALOME::SALOME_Exception& S_ex ) { + SalomeApp_Tools::QtCatchCorbaException( S_ex ); + } + catch ( ... ) { + } + + if ( res ) { + SMESHGUI::Modified(); + update( UF_ObjBrowser | UF_Model ); + myDlg->setNewMeshName( SMESH::UniqueName( "Mesh_1" ) ); + myDlg->setGroupName( SMESH::UniqueName( "Group" ) ); + } + else { + SUIT_MessageBox::warning( myDlg, tr( "SMESH_ERROR" ), tr( "SMESH_OPERATION_FAILED" ) ); + } + + return res; } diff --git a/src/SMESHGUI/SMESHGUI_Make2DFrom3DOp.h b/src/SMESHGUI/SMESHGUI_Make2DFrom3DOp.h index f2ef2d9fd..23bab5e61 100644 --- a/src/SMESHGUI/SMESHGUI_Make2DFrom3DOp.h +++ b/src/SMESHGUI/SMESHGUI_Make2DFrom3DOp.h @@ -16,69 +16,96 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // - -// SMESH SMESHGUI : GUI for SMESH component // File : SMESHGUI_Make2DFrom3D.h -// Author : Open CASCADE S.A.S. -// +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) + #ifndef SMESHGUI_Make2DFrom3DOp_H #define SMESHGUI_Make2DFrom3DOp_H // SMESH includes #include "SMESH_SMESHGUI.hxx" - #include "SMESHGUI_Dialog.h" -#include "SMESHGUI_Operation.h" +#include "SMESHGUI_SelectionOp.h" -// IDL includes #include -#include CORBA_SERVER_HEADER(SMESH_Mesh) +#include CORBA_SERVER_HEADER(SMESH_MeshEditor) -class QFrame; -class SMESHGUI_MeshInfosBox; +class QCheckBox; +class QLineEdit; +class QRadioButton; /*! * \brief Dialog to show result mesh statistic */ -class SMESHGUI_Make2DFrom3DDlg : public SMESHGUI_Dialog +class SMESHGUI_EXPORT SMESHGUI_Make2DFrom3DDlg : public SMESHGUI_Dialog { Q_OBJECT - public: +public: + enum { Mesh }; + SMESHGUI_Make2DFrom3DDlg( QWidget* ); virtual ~SMESHGUI_Make2DFrom3DDlg(); - void SetMeshName(const QString& theName); - void SetMeshInfo(const SMESH::long_array& theInfo); - - private: - QFrame* createMainFrame( QWidget* ); - - private: - QLabel* myMeshName; - SMESHGUI_MeshInfosBox* myFullInfo; + SMESH::Bnd_Dimension mode() const; + + bool needNewMesh() const; + QString getNewMeshName() const; + void setNewMeshName( const QString& ); + + bool needGroup() const; + QString getGroupName() const; + void setGroupName( const QString& ); + + bool copySource() const; + bool copyMissingOnly() const; + +private slots: + void onTargetChanged(); + void onGroupChecked(); + +private: + QRadioButton* my2dFrom3dRB; + QRadioButton* my1dFrom2dRB; + QRadioButton* my1dFrom3dRB; + QRadioButton* myThisMeshRB; + QRadioButton* myNewMeshRB; + QLineEdit* myMeshName; + QCheckBox* myCopyCheck; + QCheckBox* myMissingCheck; + QCheckBox* myGroupCheck; + QLineEdit* myGroupName; }; - /*! * \brief Operation to compute 2D mesh on 3D */ -class SMESHGUI_Make2DFrom3DOp : public SMESHGUI_Operation +class SMESHGUI_EXPORT SMESHGUI_Make2DFrom3DOp : public SMESHGUI_SelectionOp { - public: + Q_OBJECT + +public: SMESHGUI_Make2DFrom3DOp(); virtual ~SMESHGUI_Make2DFrom3DOp(); - protected: + virtual LightApp_Dialog* dlg() const; + +protected: virtual void startOperation(); + virtual void selectionDone(); + virtual SUIT_SelectionFilter* createFilter( const int ) const; + bool isValid( QString& ) const; + +protected slots: + virtual bool onApply(); - private: +private: bool compute2DMesh(); - private: - SMESH::SMESH_Mesh_var myMesh; +private: + SMESH::SMESH_IDSource_var mySrc; QPointer myDlg; }; diff --git a/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx b/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx index ee35301f0..36aa22bb4 100644 --- a/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx @@ -92,7 +92,7 @@ SMESHGUI_MakeNodeAtPointDlg::SMESHGUI_MakeNodeAtPointDlg() setWindowTitle(tr("CAPTION")); QVBoxLayout* aDlgLay = new QVBoxLayout (mainFrame()); - aDlgLay->setMargin(MARGIN);; + aDlgLay->setMargin(0); aDlgLay->setSpacing(SPACING); QWidget* aMainFrame = createMainFrame (mainFrame()); @@ -116,7 +116,7 @@ QWidget* SMESHGUI_MakeNodeAtPointDlg::createMainFrame (QWidget* theParent) // constructor - QGroupBox* aPixGrp = new QGroupBox(tr("MESH_PASS_THROUGH_POINT"), aFrame); + QGroupBox* aPixGrp = new QGroupBox(tr("MOVE_NODE"), aFrame); QButtonGroup* aBtnGrp = new QButtonGroup(this); QHBoxLayout* aPixGrpLayout = new QHBoxLayout(aPixGrp); aPixGrpLayout->setMargin(MARGIN); @@ -130,7 +130,7 @@ QWidget* SMESHGUI_MakeNodeAtPointDlg::createMainFrame (QWidget* theParent) // coordinates - QGroupBox* aCoordGrp = new QGroupBox(tr("SMESH_COORDINATES"), aFrame); + QGroupBox* aCoordGrp = new QGroupBox(tr("DESTINATION"), aFrame); QHBoxLayout* aCoordGrpLayout = new QHBoxLayout(aCoordGrp); aCoordGrpLayout->setMargin(MARGIN); aCoordGrpLayout->setSpacing(SPACING); @@ -160,19 +160,6 @@ QWidget* SMESHGUI_MakeNodeAtPointDlg::createMainFrame (QWidget* theParent) aCoordGrpLayout->addWidget(aZLabel); aCoordGrpLayout->addWidget(myZ); - // Method selection - - QGroupBox* aMethodGrp = new QGroupBox(tr("METHOD"), aFrame); - QHBoxLayout* aMethodGrpLayout = new QHBoxLayout(aMethodGrp); - aMethodGrpLayout->setMargin(MARGIN); - aMethodGrpLayout->setSpacing(SPACING); - - myMoveRBtn = new QRadioButton(tr("MOVE_EXISTING_METHOD"), aMethodGrp); - myCreateRBtn = new QRadioButton(tr("CREATE_NEW_METHOD"), aMethodGrp); - - aMethodGrpLayout->addWidget(myMoveRBtn); - aMethodGrpLayout->addWidget(myCreateRBtn); - // node ID myNodeToMoveGrp = new QGroupBox(tr("NODE_2MOVE"), aFrame); @@ -183,6 +170,62 @@ QWidget* SMESHGUI_MakeNodeAtPointDlg::createMainFrame (QWidget* theParent) myIdBtn->setCheckable(true); myId = new QLineEdit(myNodeToMoveGrp); myId->setValidator(new SMESHGUI_IdValidator(this, 1)); + + QWidget* aCoordWidget = new QWidget(myNodeToMoveGrp); + + QLabel* aCurrentXLabel = new QLabel(tr("SMESH_X"), aCoordWidget); + myCurrentX = new SMESHGUI_SpinBox(aCoordWidget); + myCurrentX->setButtonSymbols(QAbstractSpinBox::NoButtons); + myCurrentX->setReadOnly(true); + + QLabel* aCurrentYLabel = new QLabel(tr("SMESH_Y"), aCoordWidget); + myCurrentY = new SMESHGUI_SpinBox(aCoordWidget); + myCurrentY->setButtonSymbols(QAbstractSpinBox::NoButtons); + myCurrentY->setReadOnly(true); + + QLabel* aCurrentZLabel = new QLabel(tr("SMESH_Z"), aCoordWidget); + myCurrentZ = new SMESHGUI_SpinBox(aCoordWidget); + myCurrentZ->setButtonSymbols(QAbstractSpinBox::NoButtons); + myCurrentZ->setReadOnly(true); + + QLabel* aDXLabel = new QLabel(tr("SMESH_DX"), aCoordWidget); + myDX = new SMESHGUI_SpinBox(aCoordWidget); + myDX->setButtonSymbols(QAbstractSpinBox::NoButtons); + myDX->setReadOnly(true); + + QLabel* aDYLabel = new QLabel(tr("SMESH_DY"), aCoordWidget); + myDY = new SMESHGUI_SpinBox(aCoordWidget); + myDY->setButtonSymbols(QAbstractSpinBox::NoButtons); + myDY->setReadOnly(true); + + QLabel* aDZLabel = new QLabel(tr("SMESH_DZ"), aCoordWidget); + myDZ = new SMESHGUI_SpinBox(aCoordWidget); + myDZ->setButtonSymbols(QAbstractSpinBox::NoButtons); + myDZ->setReadOnly(true); + + myCurrentX->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision"); + myCurrentY->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision"); + myCurrentZ->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision"); + myDX->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision"); + myDY->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision"); + myDZ->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision"); + + QGridLayout* aCoordLayout = new QGridLayout(aCoordWidget); + aCoordLayout->setMargin(0); + aCoordLayout->setSpacing(SPACING); + aCoordLayout->addWidget(aCurrentXLabel, 0, 0); + aCoordLayout->addWidget(myCurrentX, 0, 1); + aCoordLayout->addWidget(aCurrentYLabel, 0, 2); + aCoordLayout->addWidget(myCurrentY, 0, 3); + aCoordLayout->addWidget(aCurrentZLabel, 0, 4); + aCoordLayout->addWidget(myCurrentZ, 0, 5); + aCoordLayout->addWidget(aDXLabel, 1, 0); + aCoordLayout->addWidget(myDX, 1, 1); + aCoordLayout->addWidget(aDYLabel, 1, 2); + aCoordLayout->addWidget(myDY, 1, 3); + aCoordLayout->addWidget(aDZLabel, 1, 4); + aCoordLayout->addWidget(myDZ, 1, 5); + myAutoSearchChkBox = new QCheckBox( tr("AUTO_SEARCH"), myNodeToMoveGrp); myPreviewChkBox = new QCheckBox( tr("PREVIEW"), myNodeToMoveGrp); @@ -193,22 +236,19 @@ QWidget* SMESHGUI_MakeNodeAtPointDlg::createMainFrame (QWidget* theParent) myNodeToMoveGrpLayout->addWidget( idLabel, 0, 0 ); myNodeToMoveGrpLayout->addWidget( myIdBtn, 0, 1 ); myNodeToMoveGrpLayout->addWidget( myId, 0, 2 ); - myNodeToMoveGrpLayout->addWidget( myAutoSearchChkBox, 1, 0, 1, 3 ); - myNodeToMoveGrpLayout->addWidget( myPreviewChkBox, 2, 0, 1, 3 ); + myNodeToMoveGrpLayout->addWidget( aCoordWidget, 1, 0, 1, 3 ); + myNodeToMoveGrpLayout->addWidget( myAutoSearchChkBox, 2, 0, 1, 3 ); + myNodeToMoveGrpLayout->addWidget( myPreviewChkBox, 3, 0, 1, 3 ); QVBoxLayout* aLay = new QVBoxLayout(aFrame); aLay->addWidget(aPixGrp); aLay->addWidget(aCoordGrp); - aLay->addWidget(aMethodGrp); aLay->addWidget(myNodeToMoveGrp); connect(myCoordBtn, SIGNAL (toggled(bool)), this, SLOT(ButtonToggled(bool))); - connect(myMoveRBtn, SIGNAL (toggled(bool)), this, SLOT(ButtonToggled(bool))); - connect(myCreateRBtn, SIGNAL (toggled(bool)), this, SLOT(ButtonToggled(bool))); connect(myIdBtn, SIGNAL (toggled(bool)), this, SLOT(ButtonToggled(bool))); connect(myAutoSearchChkBox, SIGNAL (toggled(bool)), this, SLOT(ButtonToggled(bool))); - myMoveRBtn->setChecked(true); myIdBtn->setChecked(true); myAutoSearchChkBox->setChecked(true); @@ -235,19 +275,16 @@ void SMESHGUI_MakeNodeAtPointDlg::ButtonToggled (bool on) { myCoordBtn->setChecked( !on ); } - else if ( aSender == myMoveRBtn ) // move node method - { - myNodeToMoveGrp->setEnabled( true ); - } - else if ( aSender == myCreateRBtn ) // create node method - { - myNodeToMoveGrp->setEnabled( false ); - myCoordBtn->setChecked( true ); - } } if ( aSender == myAutoSearchChkBox ) // automatic node search { if ( on ) { + myCurrentX->SetValue(0); + myCurrentY->SetValue(0); + myCurrentZ->SetValue(0); + myDX->SetValue(0); + myDY->SetValue(0); + myDZ->SetValue(0); myId->setText(""); myId->setReadOnly ( true ); myIdBtn->setChecked( false ); @@ -281,8 +318,6 @@ SMESHGUI_MakeNodeAtPointOp::SMESHGUI_MakeNodeAtPointOp() connect(myDlg->myId,SIGNAL (textChanged(const QString&)),SLOT(redisplayPreview())); connect(myDlg->myPreviewChkBox, SIGNAL (toggled(bool)),SLOT(redisplayPreview())); connect(myDlg->myAutoSearchChkBox,SIGNAL (toggled(bool)),SLOT(redisplayPreview())); - connect(myDlg->myMoveRBtn, SIGNAL (toggled(bool)),SLOT(redisplayPreview())); - connect(myDlg->myCreateRBtn, SIGNAL (toggled(bool)),SLOT(redisplayPreview())); } //======================================================================= @@ -321,6 +356,12 @@ void SMESHGUI_MakeNodeAtPointOp::startOperation() myDlg->myX->SetValue(0); myDlg->myY->SetValue(0); myDlg->myZ->SetValue(0); + myDlg->myCurrentX->SetValue(0); + myDlg->myCurrentY->SetValue(0); + myDlg->myCurrentZ->SetValue(0); + myDlg->myDX->SetValue(0); + myDlg->myDY->SetValue(0); + myDlg->myDZ->SetValue(0); myDlg->myId->setText(""); myDlg->show(); @@ -394,21 +435,18 @@ bool SMESHGUI_MakeNodeAtPointOp::onApply() if (aMeshEditor->_is_nil()) return true; - int aResult = 0; - if ( myDlg->myCreateRBtn->isChecked() ) - { - aResult = aMeshEditor->AddNode(myDlg->myX->GetValue(), - myDlg->myY->GetValue(), - myDlg->myZ->GetValue()); - } - else - { - int anId = myDlg->myId->text().toInt(); - aResult = aMeshEditor->MoveClosestNodeToPoint(myDlg->myX->GetValue(), - myDlg->myY->GetValue(), - myDlg->myZ->GetValue(), - anId); - } + bool ok; + int anId = myDlg->myId->text().toInt( &ok ); + if( !ok || anId < 1 ) + anId = aMeshEditor->FindNodeClosestTo(myDlg->myX->GetValue(), + myDlg->myY->GetValue(), + myDlg->myZ->GetValue()); + + int aResult = aMeshEditor->MoveNode(anId, + myDlg->myX->GetValue(), + myDlg->myY->GetValue(), + myDlg->myZ->GetValue() ); + if (aResult) { QStringList aParameters; @@ -417,6 +455,12 @@ bool SMESHGUI_MakeNodeAtPointOp::onApply() aParameters << myDlg->myZ->text(); aMesh->SetParameters( aParameters.join(":").toLatin1().constData() ); + myDlg->myCurrentX->SetValue(0); + myDlg->myCurrentY->SetValue(0); + myDlg->myCurrentZ->SetValue(0); + myDlg->myDX->SetValue(0); + myDlg->myDY->SetValue(0); + myDlg->myDZ->SetValue(0); myDlg->myId->setText(""); SALOME_ListIO aList; @@ -446,7 +490,6 @@ bool SMESHGUI_MakeNodeAtPointOp::isValid( QString& msg ) { bool ok = true; if ( myMeshActor && - myDlg->myMoveRBtn->isChecked() && !myDlg->myAutoSearchChkBox->isChecked() ) { ok = false; @@ -525,6 +568,21 @@ void SMESHGUI_MakeNodeAtPointOp::onSelectionDone() myNoPreview = false; redisplayPreview(); } + + if (const SMDS_MeshNode* aCurrentNode = aMesh->FindNode(myDlg->myId->text().toInt())) { + double x = aCurrentNode->X(); + double y = aCurrentNode->Y(); + double z = aCurrentNode->Z(); + double dx = myDlg->myX->GetValue() - x; + double dy = myDlg->myY->GetValue() - y; + double dz = myDlg->myZ->GetValue() - z; + myDlg->myCurrentX->SetValue(x); + myDlg->myCurrentY->SetValue(y); + myDlg->myCurrentZ->SetValue(z); + myDlg->myDX->SetValue(dx); + myDlg->myDY->SetValue(dy); + myDlg->myDZ->SetValue(dz); + } } } } @@ -547,15 +605,22 @@ void SMESHGUI_MakeNodeAtPointOp::redisplayPreview() SMESH::MeshPreviewStruct_var aMeshPreviewStruct; bool moveShown = false; - if ( myDlg->myMoveRBtn->isChecked() && // Move method - myMeshActor) + if ( myMeshActor) { const bool autoSearch = myDlg->myAutoSearchChkBox->isChecked(); const bool preview = myDlg->myPreviewChkBox->isChecked(); if ( autoSearch ) + { + myDlg->myCurrentX->SetValue(0); + myDlg->myCurrentY->SetValue(0); + myDlg->myCurrentZ->SetValue(0); + myDlg->myDX->SetValue(0); + myDlg->myDY->SetValue(0); + myDlg->myDZ->SetValue(0); myDlg->myId->setText(""); + } QString msg; - if ( preview && ( autoSearch || isValid( msg ) )) + if ( autoSearch || isValid( msg ) ) { try { SMESH::SMESH_Mesh_var aMesh = SMESH::GetMeshByIO(myMeshActor->getIO()); @@ -565,11 +630,19 @@ void SMESHGUI_MakeNodeAtPointOp::redisplayPreview() { SUIT_OverrideCursor aWaitCursor; + int anId = 0; + if ( autoSearch ) + anId = aPreviewer->FindNodeClosestTo(myDlg->myX->GetValue(), + myDlg->myY->GetValue(), + myDlg->myZ->GetValue()); + else + anId = myDlg->myId->text().toInt(); + // find id and/or just compute preview - int anId = aPreviewer->MoveClosestNodeToPoint(myDlg->myX->GetValue(), - myDlg->myY->GetValue(), - myDlg->myZ->GetValue(), - myDlg->myId->text().toInt()); + aPreviewer->MoveNode(anId, + myDlg->myX->GetValue(), + myDlg->myY->GetValue(), + myDlg->myZ->GetValue()); if ( autoSearch ) { // set found id QString idTxt("%1"); if ( anId > 0 ) @@ -578,6 +651,24 @@ void SMESHGUI_MakeNodeAtPointOp::redisplayPreview() idTxt = ""; myDlg->myId->setText( idTxt ); } + + SMESH::double_array* aXYZ = aMesh->GetNodeXYZ( anId ); + if( aXYZ && aXYZ->length() >= 3 ) + { + double x = aXYZ->operator[](0); + double y = aXYZ->operator[](1); + double z = aXYZ->operator[](2); + double dx = myDlg->myX->GetValue() - x; + double dy = myDlg->myY->GetValue() - y; + double dz = myDlg->myZ->GetValue() - z; + myDlg->myCurrentX->SetValue(x); + myDlg->myCurrentY->SetValue(y); + myDlg->myCurrentZ->SetValue(z); + myDlg->myDX->SetValue(dx); + myDlg->myDY->SetValue(dy); + myDlg->myDZ->SetValue(dz); + } + if ( preview ) { // fill preview data aMeshPreviewStruct = aPreviewer->GetPreviewData(); moveShown = ( anId > 0 ); diff --git a/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.h b/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.h index 68408d990..8774c8bfa 100644 --- a/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.h +++ b/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.h @@ -36,7 +36,6 @@ class QGroupBox; class QLineEdit; class QPushButton; class QCheckBox; -class QRadioButton; class SMESHGUI_SpinBox; class SMESHGUI_MeshEditPreview; class SMESHGUI_MakeNodeAtPointDlg; @@ -98,11 +97,15 @@ private: SMESHGUI_SpinBox* myX; SMESHGUI_SpinBox* myY; SMESHGUI_SpinBox* myZ; - QRadioButton* myMoveRBtn; - QRadioButton* myCreateRBtn; QGroupBox* myNodeToMoveGrp; QPushButton* myIdBtn; QLineEdit* myId; + SMESHGUI_SpinBox* myCurrentX; + SMESHGUI_SpinBox* myCurrentY; + SMESHGUI_SpinBox* myCurrentZ; + SMESHGUI_SpinBox* myDX; + SMESHGUI_SpinBox* myDY; + SMESHGUI_SpinBox* myDZ; QCheckBox* myAutoSearchChkBox; QCheckBox* myPreviewChkBox; diff --git a/src/SMESHGUI/SMESHGUI_Measurements.cxx b/src/SMESHGUI/SMESHGUI_Measurements.cxx new file mode 100644 index 000000000..b07c08dc4 --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_Measurements.cxx @@ -0,0 +1,1231 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SMESHGUI_Measurements.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) + +#include "SMESHGUI_Measurements.h" + +#include "SMESH_Actor.h" +#include "SMESHGUI.h" +#include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_Utils.h" +#include "SMESHGUI_VTKUtils.h" +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include CORBA_SERVER_HEADER(SMESH_MeshEditor) +#include CORBA_SERVER_HEADER(SMESH_Measurements) + +const int SPACING = 6; // layout spacing +const int MARGIN = 9; // layout margin +const int MAX_NB_FOR_EDITOR = 40; // max nb of items in the ID list editor field + +// Uncomment as soon as elements are supported by Min Distance operation +//#define MINDIST_ENABLE_ELEMENT + +// Uncomment as soon as objects are supported by Min Distance operation +//#define MINDIST_ENABLE_OBJECT + +/*! + \class SMESHGUI_MinDistance + \brief Minimum distance measurement widget. + + Widget to calculate minimum distance between two objects. +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +SMESHGUI_MinDistance::SMESHGUI_MinDistance( QWidget* parent ) +: QWidget( parent ), myCurrentTgt( FirstTgt ), myFirstActor( 0 ), mySecondActor( 0 ), myPreview( 0 ) +{ + QGroupBox* aFirstTgtGrp = new QGroupBox( tr( "FIRST_TARGET" ), this ); + QRadioButton* aFNode = new QRadioButton( tr( "NODE" ), aFirstTgtGrp ); + QRadioButton* aFElem = new QRadioButton( tr( "ELEMENT" ), aFirstTgtGrp ); + QRadioButton* aFObject = new QRadioButton( tr( "OBJECT" ), aFirstTgtGrp ); + myFirstTgt = new QLineEdit( aFirstTgtGrp ); + + QGridLayout* fl = new QGridLayout( aFirstTgtGrp ); + fl->setMargin( MARGIN ); + fl->setSpacing( SPACING ); + fl->addWidget( aFNode, 0, 0 ); + fl->addWidget( aFElem, 0, 1 ); + fl->addWidget( aFObject, 0, 2 ); + fl->addWidget( myFirstTgt, 1, 0, 1, 3 ); + + myFirst = new QButtonGroup( this ); + myFirst->addButton( aFNode, NodeTgt ); + myFirst->addButton( aFElem, ElementTgt ); + myFirst->addButton( aFObject, ObjectTgt ); + + QGroupBox* aSecondTgtGrp = new QGroupBox( tr( "SECOND_TARGET" ), this ); + QRadioButton* aSOrigin = new QRadioButton( tr( "ORIGIN" ), aSecondTgtGrp ); + QRadioButton* aSNode = new QRadioButton( tr( "NODE" ), aSecondTgtGrp ); + QRadioButton* aSElem = new QRadioButton( tr( "ELEMENT" ), aSecondTgtGrp ); + QRadioButton* aSObject = new QRadioButton( tr( "OBJECT" ), aSecondTgtGrp ); + mySecondTgt = new QLineEdit( aSecondTgtGrp ); + + QGridLayout* sl = new QGridLayout( aSecondTgtGrp ); + sl->setMargin( MARGIN ); + sl->setSpacing( SPACING ); + sl->addWidget( aSOrigin, 0, 0 ); + sl->addWidget( aSNode, 0, 1 ); + sl->addWidget( aSElem, 0, 2 ); + sl->addWidget( aSObject, 0, 3 ); + sl->addWidget( mySecondTgt, 1, 0, 1, 4 ); + + mySecond = new QButtonGroup( this ); + mySecond->addButton( aSOrigin, OriginTgt ); + mySecond->addButton( aSNode, NodeTgt ); + mySecond->addButton( aSElem, ElementTgt ); + mySecond->addButton( aSObject, ObjectTgt ); + + QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this ); + + QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this ); + QLabel* aDxLab = new QLabel( "dX", aResults ); + myDX = new QLineEdit( aResults ); + QLabel* aDyLab = new QLabel( "dY", aResults ); + myDY = new QLineEdit( aResults ); + QLabel* aDzLab = new QLabel( "dZ", aResults ); + myDZ = new QLineEdit( aResults ); + QLabel* aDistLab = new QLabel( tr( "DISTANCE" ), aResults ); + myDistance = new QLineEdit( aResults ); + + QGridLayout* rl = new QGridLayout( aResults ); + rl->setMargin( MARGIN ); + rl->setSpacing( SPACING ); + rl->addWidget( aDxLab, 0, 0 ); + rl->addWidget( myDX, 0, 1 ); + rl->addWidget( aDyLab, 1, 0 ); + rl->addWidget( myDY, 1, 1 ); + rl->addWidget( aDzLab, 2, 0 ); + rl->addWidget( myDZ, 2, 1 ); + rl->addWidget( aDistLab, 0, 2 ); + rl->addWidget( myDistance, 0, 3 ); + + QGridLayout* l = new QGridLayout( this ); + l->setMargin( MARGIN ); + l->setSpacing( SPACING ); + + l->addWidget( aFirstTgtGrp, 0, 0, 1, 2 ); + l->addWidget( aSecondTgtGrp, 1, 0, 1, 2 ); + l->addWidget( aCompute, 2, 0 ); + l->addWidget( aResults, 3, 0, 1, 2 ); + l->setColumnStretch( 1, 5 ); + l->setRowStretch( 4, 5 ); + + aFNode->setChecked( true ); + aSOrigin->setChecked( true ); +#ifndef MINDIST_ENABLE_ELEMENT + aFElem->setEnabled( false ); // NOT AVAILABLE YET + aSElem->setEnabled( false ); // NOT AVAILABLE YET +#endif +#ifndef MINDIST_ENABLE_OBJECT + aFObject->setEnabled( false ); // NOT AVAILABLE YET + aSObject->setEnabled( false ); // NOT AVAILABLE YET +#endif + myDX->setReadOnly( true ); + myDY->setReadOnly( true ); + myDZ->setReadOnly( true ); + myDistance->setReadOnly( true ); + + myValidator = new SMESHGUI_IdValidator( this, 1 ); + + myFirstTgt->installEventFilter( this ); + mySecondTgt->installEventFilter( this ); + + connect( myFirst, SIGNAL( buttonClicked( int ) ), this, SLOT( firstChanged() ) ); + connect( mySecond, SIGNAL( buttonClicked( int ) ), this, SLOT( secondChanged() ) ); + connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) ); + connect( myFirstTgt, SIGNAL( textEdited( QString ) ), this, SLOT( firstEdited() ) ); + connect( mySecondTgt, SIGNAL( textEdited( QString ) ), this, SLOT( secondEdited() ) ); + + QList filters; + filters.append( new SMESH_TypeFilter( MESHorSUBMESH ) ); + filters.append( new SMESH_TypeFilter( GROUP ) ); + myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR ); + + mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt ); + clear(); + + //setTarget( FirstTgt ); +} + +/*! + \brief Destructor +*/ +SMESHGUI_MinDistance::~SMESHGUI_MinDistance() +{ + erasePreview(); + if ( myPreview ) + myPreview->Delete(); +} + +/*! + \brief Event filter + \param o object + \param o event + \return \c true if event is filtered or \c false otherwise +*/ +bool SMESHGUI_MinDistance::eventFilter( QObject* o, QEvent* e ) +{ + if ( e->type() == QEvent::FocusIn ) { + if ( o == myFirstTgt ) + setTarget( FirstTgt ); + else if ( o == mySecondTgt ) + setTarget( SecondTgt ); + } + return QWidget::eventFilter( o, e ); +} + +/*! + \brief Setup selection mode depending on the current widget state +*/ +void SMESHGUI_MinDistance::updateSelection() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + + disconnect( selMgr, 0, this, 0 ); + selMgr->clearFilters(); + + bool nodeMode = ( myCurrentTgt == FirstTgt && myFirst->checkedId() == NodeTgt ) || + ( myCurrentTgt == SecondTgt && mySecond->checkedId() == NodeTgt ); + bool elemMode = ( myCurrentTgt == FirstTgt && myFirst->checkedId() == ElementTgt ) || + ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ElementTgt ); + bool objMode = ( myCurrentTgt == FirstTgt && myFirst->checkedId() == ObjectTgt ) || + ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ObjectTgt ) || + ( myCurrentTgt == NoTgt ); + + if ( nodeMode ) { + SMESH::SetPointRepresentation( true ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( NodeSelection ); + } + else if ( elemMode ) { + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( CellSelection ); + } + else if ( objMode ) { + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( ActorSelection ); + selMgr->installFilter( myFilter ); + } + + connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) ); + + if ( myCurrentTgt == FirstTgt ) + firstEdited(); + else if ( myCurrentTgt == SecondTgt ) + secondEdited(); + + //selectionChanged(); +} + +/*! + \brief Deactivate widget +*/ +void SMESHGUI_MinDistance::deactivate() +{ + disconnect( SMESHGUI::selectionMgr(), 0, this, 0 ); +} + +/*! + \brief Set current target for selection + \param target new target ID +*/ +void SMESHGUI_MinDistance::setTarget( int target ) +{ + if ( myCurrentTgt != target ) { + myCurrentTgt = target; + updateSelection(); + } +} + +/*! + \brief Erase preview actor +*/ +void SMESHGUI_MinDistance::erasePreview() +{ + SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(); + if ( aViewWindow && myPreview ) { + aViewWindow->RemoveActor( myPreview ); + aViewWindow->Repaint(); + } +} + +/*! + \brief Display preview actor +*/ +void SMESHGUI_MinDistance::displayPreview() +{ + SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(); + if ( aViewWindow && myPreview ) { + aViewWindow->AddActor( myPreview ); + aViewWindow->Repaint(); + } +} + +/*! + \brief Create preview actor + \param x1 X coordinate of first point + \param y1 X coordinate of first point + \param z1 Y coordinate of first point + \param x2 Y coordinate of second point + \param y2 Z coordinate of second point + \param z2 Z coordinate of second point +*/ +void SMESHGUI_MinDistance::createPreview( double x1, double y1, double z1, double x2, double y2, double z2 ) +{ + if ( myPreview ) + myPreview->Delete(); + + vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New(); + // create points + vtkPoints* aPoints = vtkPoints::New(); + aPoints->SetNumberOfPoints( 2 ); + aPoints->SetPoint( 0, x1, y1, z1 ); + aPoints->SetPoint( 1, x2, y2, z2 ); + aGrid->SetPoints( aPoints ); + aPoints->Delete(); + // create cells + vtkIdList* anIdList = vtkIdList::New(); + anIdList->SetNumberOfIds( 2 ); + vtkCellArray* aCells = vtkCellArray::New(); + aCells->Allocate( 2, 0); + vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New(); + aCellTypesArray->SetNumberOfComponents( 1 ); + aCellTypesArray->Allocate( 1 ); + anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->Delete(); + VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New(); + aCellLocationsArray->SetNumberOfComponents( 1 ); + aCellLocationsArray->SetNumberOfTuples( 1 ); + aCells->InitTraversal(); + for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ ) + aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) ); + aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells ); + aCellLocationsArray->Delete(); + aCellTypesArray->Delete(); + aCells->Delete(); + // create actor + vtkDataSetMapper* aMapper = vtkDataSetMapper::New(); + aMapper->SetInput( aGrid ); + aGrid->Delete(); + myPreview = SALOME_Actor::New(); + myPreview->PickableOff(); + myPreview->SetMapper( aMapper ); + aMapper->Delete(); + vtkProperty* aProp = vtkProperty::New(); + aProp->SetRepresentationToWireframe(); + aProp->SetColor( 250, 0, 250 ); + aProp->SetPointSize( 5 ); + aProp->SetLineWidth( 3 ); + myPreview->SetProperty( aProp ); + aProp->Delete(); +} + +/*! + \brief Called when selection is changed +*/ +void SMESHGUI_MinDistance::selectionChanged() +{ + SUIT_OverrideCursor wc; + + SALOME_ListIO selected; + SMESHGUI::selectionMgr()->selectedObjects( selected ); + + if ( selected.Extent() == 1 ) { + Handle(SALOME_InteractiveObject) IO = selected.First(); + SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface( IO ); + if ( !CORBA::is_nil( obj ) ) { + if ( myCurrentTgt == FirstTgt ) { + myFirstSrc = obj; + myFirstActor = SMESH::FindActorByEntry( IO->getEntry() ); + if ( myFirst->checkedId() == ObjectTgt ) { + QString aName; + SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName ); + myFirstTgt->setText( aName ); + } + else { + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + QString ID; + int nb = 0; + if ( myFirstActor && selector ) { + nb = myFirst->checkedId() == NodeTgt ? + SMESH::GetNameOfSelectedElements( selector, IO, ID ) : + SMESH::GetNameOfSelectedNodes( selector, IO, ID ); + } + if ( nb == 1 ) + myFirstTgt->setText( ID.trimmed() ); + else + myFirstTgt->clear(); + } + } + else if ( myCurrentTgt == SecondTgt ) { + mySecondSrc = obj; + mySecondActor = SMESH::FindActorByEntry( IO->getEntry() ); + if ( mySecond->checkedId() == ObjectTgt ) { + QString aName; + SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName ); + mySecondTgt->setText( aName ); + } + else { + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + QString ID; + int nb = 0; + if ( mySecondActor && selector ) { + nb = mySecond->checkedId() == NodeTgt ? + SMESH::GetNameOfSelectedElements( selector, IO, ID ) : + SMESH::GetNameOfSelectedNodes( selector, IO, ID ); + } + if ( nb == 1 ) + mySecondTgt->setText( ID.trimmed() ); + else + mySecondTgt->clear(); + } + } + } + } + clear(); +} + +/*! + \brief Called when first target mode is changed by the user +*/ +void SMESHGUI_MinDistance::firstChanged() +{ + myFirstSrc = SMESH::SMESH_IDSource::_nil(); + myFirstTgt->clear(); + myFirstTgt->setReadOnly( myFirst->checkedId() == ObjectTgt ); + myFirstTgt->setValidator( myFirst->checkedId() == ObjectTgt ? 0 : myValidator ); + setTarget( FirstTgt ); + updateSelection(); + clear(); +} + +/*! + \brief Called when second target mode is changed by the user +*/ +void SMESHGUI_MinDistance::secondChanged() +{ + mySecondSrc = SMESH::SMESH_IDSource::_nil(); + mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt ); + mySecondTgt->setReadOnly( mySecond->checkedId() == ObjectTgt ); + mySecondTgt->setValidator( mySecond->checkedId() == ObjectTgt ? 0 : myValidator ); + mySecondTgt->clear(); + setTarget( mySecond->checkedId() != OriginTgt ? SecondTgt : NoTgt ); + updateSelection(); + clear(); +} + +/*! + \brief Called when first target is edited by the user +*/ +void SMESHGUI_MinDistance::firstEdited() +{ + setTarget( FirstTgt ); + if ( sender() == myFirstTgt ) + clear(); + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + if ( myFirstActor && selector ) { + Handle(SALOME_InteractiveObject) IO = myFirstActor->getIO(); + if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) { + TColStd_MapOfInteger ID; + ID.Add( myFirstTgt->text().toLong() ); + selector->AddOrRemoveIndex( IO, ID, false ); + } + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->highlight( IO, true, true ); + } +} + +/*! + \brief Called when second target is edited by the user +*/ +void SMESHGUI_MinDistance::secondEdited() +{ + setTarget( SecondTgt ); + if ( sender() == mySecondTgt ) + clear(); + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + if ( mySecondActor && selector ) { + Handle(SALOME_InteractiveObject) IO = mySecondActor->getIO(); + if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) { + TColStd_MapOfInteger ID; + ID.Add( mySecondTgt->text().toLong() ); + selector->AddOrRemoveIndex( IO, ID, false ); + } + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->highlight( IO, true, true ); + } +} + +/*! + \brief Compute the minimum distance between targets +*/ +void SMESHGUI_MinDistance::compute() +{ + SUIT_OverrideCursor wc; + SMESH::SMESH_IDSource_var s1; + SMESH::SMESH_IDSource_var s2; + bool isOrigin = mySecond->checkedId() == OriginTgt; + + // process first target + if ( !CORBA::is_nil( myFirstSrc ) ) { + if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) { + SMESH::SMESH_Mesh_var m = myFirstSrc->GetMesh(); + long id = myFirstTgt->text().toLong(); + if ( !CORBA::is_nil( m ) && id ) { + SMESH::long_array_var ids = new SMESH::long_array(); + ids->length( 1 ); + ids[0] = id; + SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor(); + s1 = me->MakeIDSource( ids.in(), myFirst->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE ); + } + } + else { + s1 = myFirstSrc; + } + } + + // process second target + if ( !CORBA::is_nil( mySecondSrc ) ) { + if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) { + SMESH::SMESH_Mesh_var m = mySecondSrc->GetMesh(); + long id = mySecondTgt->text().toLong(); + if ( !CORBA::is_nil( m ) && id ) { + SMESH::long_array_var ids = new SMESH::long_array(); + ids->length( 1 ); + ids[0] = id; + SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor(); + s2 = me->MakeIDSource( ids.in(), mySecond->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE ); + } + } + else { + s2 = mySecondSrc; + } + } + + if ( !CORBA::is_nil( s1 ) && ( !CORBA::is_nil( s2 ) || isOrigin ) ) { + // compute min distance + int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); + SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements(); + SMESH::Measure result = measure->MinDistance( s1.in(), s2.in() ); + measure->Destroy(); + myDX->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myDY->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myDZ->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myDistance->setText( QString::number( result.value, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + // update preview actor + erasePreview(); + double x1, y1, z1, x2, y2, z2; + SMESH::double_array_var coord = s1->GetMesh()->GetNodeXYZ( result.node1 ); + x1 = coord[0]; y1 = coord[1]; z1 = coord[2]; + if ( isOrigin ) { + x2 = y2 = z2 = 0.; + } + else { + coord = s2->GetMesh()->GetNodeXYZ( result.node2 ); + x2 = coord[0]; y2 = coord[1]; z2 = coord[2]; + } + createPreview( x1, y1, z1, x2, y2, z2 ); + displayPreview(); + } + else { + clear(); + } +} + +/*! + \brief Reset the widget to the initial state (nullify result fields) +*/ +void SMESHGUI_MinDistance::clear() +{ + myDX->clear(); + myDY->clear(); + myDZ->clear(); + myDistance->clear(); + erasePreview(); +} + +/*! + \class SMESHGUI_BoundingBox + \brief Bounding box measurement widget. + + Widget to calculate bounding box of the selected object(s). +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +SMESHGUI_BoundingBox::SMESHGUI_BoundingBox( QWidget* parent ) +: QWidget( parent ), myActor( 0 ), myPreview( 0 ) +{ + QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE" ), this ); + QRadioButton* aObjects = new QRadioButton( tr( "OBJECTS" ), aSourceGrp ); + QRadioButton* aNodes = new QRadioButton( tr( "NODES" ), aSourceGrp ); + QRadioButton* aElements = new QRadioButton( tr( "ELEMENTS" ), aSourceGrp ); + mySource = new QLineEdit( aSourceGrp ); + + QGridLayout* fl = new QGridLayout( aSourceGrp ); + fl->setMargin( MARGIN ); + fl->setSpacing( SPACING ); + fl->addWidget( aObjects, 0, 0 ); + fl->addWidget( aNodes, 0, 1 ); + fl->addWidget( aElements, 0, 2 ); + fl->addWidget( mySource, 1, 0, 1, 3 ); + + mySourceMode = new QButtonGroup( this ); + mySourceMode->addButton( aObjects, ObjectsSrc ); + mySourceMode->addButton( aNodes, NodesSrc ); + mySourceMode->addButton( aElements, ElementsSrc ); + + QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this ); + + QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this ); + QLabel* aXminLab = new QLabel( "Xmin", aResults ); + myXmin = new QLineEdit( aResults ); + QLabel* aXmaxLab = new QLabel( "Xmax", aResults ); + myXmax = new QLineEdit( aResults ); + QLabel* aDxLab = new QLabel( "dX", aResults ); + myDX = new QLineEdit( aResults ); + QLabel* aYminLab = new QLabel( "Ymin", aResults ); + myYmin = new QLineEdit( aResults ); + QLabel* aYmaxLab = new QLabel( "Ymax", aResults ); + myYmax = new QLineEdit( aResults ); + QLabel* aDyLab = new QLabel( "dY", aResults ); + myDY = new QLineEdit( aResults ); + QLabel* aZminLab = new QLabel( "Zmin", aResults ); + myZmin = new QLineEdit( aResults ); + QLabel* aZmaxLab = new QLabel( "Zmax", aResults ); + myZmax = new QLineEdit( aResults ); + QLabel* aDzLab = new QLabel( "dZ", aResults ); + myDZ = new QLineEdit( aResults ); + + QGridLayout* rl = new QGridLayout( aResults ); + rl->setMargin( MARGIN ); + rl->setSpacing( SPACING ); + rl->addWidget( aXminLab, 0, 0 ); + rl->addWidget( myXmin, 0, 1 ); + rl->addWidget( aXmaxLab, 0, 2 ); + rl->addWidget( myXmax, 0, 3 ); + rl->addWidget( aDxLab, 0, 4 ); + rl->addWidget( myDX, 0, 5 ); + rl->addWidget( aYminLab, 1, 0 ); + rl->addWidget( myYmin, 1, 1 ); + rl->addWidget( aYmaxLab, 1, 2 ); + rl->addWidget( myYmax, 1, 3 ); + rl->addWidget( aDyLab, 1, 4 ); + rl->addWidget( myDY, 1, 5 ); + rl->addWidget( aZminLab, 2, 0 ); + rl->addWidget( myZmin, 2, 1 ); + rl->addWidget( aZmaxLab, 2, 2 ); + rl->addWidget( myZmax, 2, 3 ); + rl->addWidget( aDzLab, 2, 4 ); + rl->addWidget( myDZ, 2, 5 ); + + QGridLayout* l = new QGridLayout( this ); + l->setMargin( MARGIN ); + l->setSpacing( SPACING ); + + l->addWidget( aSourceGrp, 0, 0, 1, 2 ); + l->addWidget( aCompute, 1, 0 ); + l->addWidget( aResults, 2, 0, 1, 2 ); + l->setColumnStretch( 1, 5 ); + l->setRowStretch( 3, 5 ); + + aObjects->setChecked( true ); + myXmin->setReadOnly( true ); + myXmax->setReadOnly( true ); + myDX->setReadOnly( true ); + myYmin->setReadOnly( true ); + myYmax->setReadOnly( true ); + myDY->setReadOnly( true ); + myZmin->setReadOnly( true ); + myZmax->setReadOnly( true ); + myDZ->setReadOnly( true ); + + myValidator = new SMESHGUI_IdValidator( this ); + + connect( mySourceMode, SIGNAL( buttonClicked( int ) ), this, SLOT( sourceChanged() ) ); + connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) ); + connect( mySource, SIGNAL( textEdited( QString ) ), this, SLOT( sourceEdited() ) ); + + QList filters; + filters.append( new SMESH_TypeFilter( MESHorSUBMESH ) ); + filters.append( new SMESH_TypeFilter( GROUP ) ); + myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR ); + + clear(); +} + +/*! + \brief Destructor +*/ +SMESHGUI_BoundingBox::~SMESHGUI_BoundingBox() +{ + erasePreview(); + if ( myPreview ) + myPreview->Delete(); +} + +/*! + \brief Setup selection mode depending on the current widget state +*/ +void SMESHGUI_BoundingBox::updateSelection() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + + disconnect( selMgr, 0, this, 0 ); + selMgr->clearFilters(); + + bool nodeMode = mySourceMode->checkedId() == NodesSrc; + bool elemMode = mySourceMode->checkedId() == ElementsSrc; + bool objMode = mySourceMode->checkedId() == ObjectsSrc; + + if ( nodeMode ) { + SMESH::SetPointRepresentation( true ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( NodeSelection ); + } + else if ( elemMode ) { + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( CellSelection ); + } + else if ( objMode ) { + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( ActorSelection ); + selMgr->installFilter( myFilter ); + } + + connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) ); + + sourceEdited(); + + //selectionChanged(); +} + +/*! + \brief Deactivate widget +*/ +void SMESHGUI_BoundingBox::deactivate() +{ + disconnect( SMESHGUI::selectionMgr(), 0, this, 0 ); +} + +/*! + \brief Erase preview actor +*/ +void SMESHGUI_BoundingBox::erasePreview() +{ + SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(); + if ( aViewWindow && myPreview ) { + aViewWindow->RemoveActor( myPreview ); + aViewWindow->Repaint(); + } +} + +/*! + \brief Display preview actor +*/ +void SMESHGUI_BoundingBox::displayPreview() +{ + SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow(); + if ( aViewWindow && myPreview ) { + aViewWindow->AddActor( myPreview ); + aViewWindow->Repaint(); + } +} + +/*! + \brief Create preview actor + \param minX min X coordinate of bounding box + \param maxX max X coordinate of bounding box + \param minY min Y coordinate of bounding box + \param maxY max Y coordinate of bounding box + \param minZ min Z coordinate of bounding box + \param maxZ max Z coordinate of bounding box +*/ +void SMESHGUI_BoundingBox::createPreview( double minX, double maxX, double minY, double maxY, double minZ, double maxZ ) +{ + if ( myPreview ) + myPreview->Delete(); + + vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New(); + // create points + vtkPoints* aPoints = vtkPoints::New(); + aPoints->SetNumberOfPoints( 8 ); + aPoints->SetPoint( 0, minX, minY, minZ ); + aPoints->SetPoint( 1, maxX, minY, minZ ); + aPoints->SetPoint( 2, minX, maxY, minZ ); + aPoints->SetPoint( 3, maxX, maxY, minZ ); + aPoints->SetPoint( 4, minX, minY, maxZ ); + aPoints->SetPoint( 5, maxX, minY, maxZ ); + aPoints->SetPoint( 6, minX, maxY, maxZ ); + aPoints->SetPoint( 7, maxX, maxY, maxZ ); + aGrid->SetPoints( aPoints ); + aPoints->Delete(); + // create cells + // connectivity: 0-1 0-4 0-2 1-5 1-3 2-6 2-3 3-7 4-6 4-5 5-7 6-7 + vtkIdList* anIdList = vtkIdList::New(); + anIdList->SetNumberOfIds( 2 ); + vtkCellArray* aCells = vtkCellArray::New(); + aCells->Allocate( 2*12, 0); + vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New(); + aCellTypesArray->SetNumberOfComponents( 1 ); + aCellTypesArray->Allocate( 12 ); + anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 4 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 2 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 5 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 3 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 6 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 3 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 3 ); anIdList->SetId( 1, 7 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 6 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 5 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 5 ); anIdList->SetId( 1, 7 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->SetId( 0, 6 ); anIdList->SetId( 1, 7 ); + aCells->InsertNextCell( anIdList ); + aCellTypesArray->InsertNextValue( VTK_LINE ); + anIdList->Delete(); + VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New(); + aCellLocationsArray->SetNumberOfComponents( 1 ); + aCellLocationsArray->SetNumberOfTuples( 12 ); + aCells->InitTraversal(); + for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ ) + aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) ); + aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells ); + aCellLocationsArray->Delete(); + aCellTypesArray->Delete(); + aCells->Delete(); + // create actor + vtkDataSetMapper* aMapper = vtkDataSetMapper::New(); + aMapper->SetInput( aGrid ); + aGrid->Delete(); + myPreview = SALOME_Actor::New(); + myPreview->PickableOff(); + myPreview->SetMapper( aMapper ); + aMapper->Delete(); + vtkProperty* aProp = vtkProperty::New(); + aProp->SetRepresentationToWireframe(); + aProp->SetColor( 250, 0, 250 ); + aProp->SetPointSize( 5 ); + aProp->SetLineWidth( 3 ); + myPreview->SetProperty( aProp ); + aProp->Delete(); +} + +/*! + \brief Called when selection is changed +*/ +void SMESHGUI_BoundingBox::selectionChanged() +{ + SUIT_OverrideCursor wc; + + SALOME_ListIO selected; + SMESHGUI::selectionMgr()->selectedObjects( selected ); + + if ( selected.Extent() == 1 ) { + Handle(SALOME_InteractiveObject) IO = selected.First(); + SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface( IO ); + if ( !CORBA::is_nil( obj ) ) { + mySrc.clear(); + mySrc.append( obj ); + myActor = SMESH::FindActorByEntry( IO->getEntry() ); + if ( mySourceMode->checkedId() == ObjectsSrc ) { + QString aName; + SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName ); + mySource->setText( aName ); + } + else { + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + QString ID; + int nb = 0; + if ( myActor && selector ) { + nb = mySourceMode->checkedId() == NodesSrc ? + SMESH::GetNameOfSelectedElements( selector, IO, ID ) : + SMESH::GetNameOfSelectedNodes( selector, IO, ID ); + } + if ( nb > 0 ) { + myIDs = ID.trimmed(); + if ( nb < MAX_NB_FOR_EDITOR ) { + mySource->setReadOnly( false ); + if ( mySource->validator() != myValidator ) + mySource->setValidator( myValidator ); + mySource->setText( ID.trimmed() ); + } + else { + mySource->setReadOnly( true ); + mySource->setValidator( 0 ); + mySource->setText( tr( "SELECTED_NB_OBJ" ).arg( nb ) + .arg( mySourceMode->checkedId() == NodesSrc ? tr( "NB_NODES" ) : tr( "NB_ELEMENTS") ) ); + } + } + else { + myIDs = ""; + mySource->clear(); + mySource->setReadOnly( false ); + mySource->setValidator( myValidator ); + } + } + } + } + else if ( selected.Extent() > 1 ) { + myIDs = ""; + SALOME_ListIteratorOfListIO It( selected ); + mySrc.clear(); + myActor = 0; + if ( mySourceMode->checkedId() == ObjectsSrc ) { + for( ; It.More(); It.Next()){ + Handle(SALOME_InteractiveObject) IO = It.Value(); + SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface( IO ); + if ( !CORBA::is_nil( obj ) ) { + mySrc.append( obj ); + } + } + QString aName; + SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName ); + mySource->setText( aName ); + } + else { + mySource->clear(); + } + } + clear(); +} + +/*! + \brief Called when source mode is changed by the user +*/ +void SMESHGUI_BoundingBox::sourceChanged() +{ + myIDs = ""; + mySource->clear(); + mySource->setReadOnly( mySourceMode->checkedId() == ObjectsSrc ); + mySource->setValidator( mySourceMode->checkedId() == ObjectsSrc ? 0 : myValidator ); + updateSelection(); + clear(); +} + +/*! + \brief Called when source mode is edited by the user +*/ +void SMESHGUI_BoundingBox::sourceEdited() +{ + if ( sender() == mySource ) + clear(); + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + if ( myActor && selector ) { + Handle(SALOME_InteractiveObject) IO = myActor->getIO(); + if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) { + TColStd_MapOfInteger ID; + if ( !mySource->isReadOnly() ) + myIDs = mySource->text(); + QStringList ids = myIDs.split( " ", QString::SkipEmptyParts ); + foreach ( QString id, ids ) + ID.Add( id.trimmed().toLong() ); + selector->AddOrRemoveIndex( IO, ID, false ); + } + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->highlight( IO, true, true ); + } +} + +/*! + \brief Calculate bounding box of the selected object(s) +*/ +void SMESHGUI_BoundingBox::compute() +{ + SUIT_OverrideCursor wc; + SMESH::ListOfIDSources_var srcList = new SMESH::ListOfIDSources(); + if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) { + if ( mySrc.count() > 0 && !CORBA::is_nil( mySrc[0] ) ) { + SMESH::SMESH_Mesh_var m = mySrc[0]->GetMesh(); + QStringList ids = myIDs.split( " ", QString::SkipEmptyParts ); + if ( !CORBA::is_nil( m ) && ids.count() > 0 ) { + SMESH::long_array_var ids_in = new SMESH::long_array(); + ids_in->length( ids.count() ); + for( int i = 0; i < ids.count(); i++ ) + ids_in[i] = ids[i].trimmed().toLong(); + SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor(); + SMESH::SMESH_IDSource_var s = me->MakeIDSource( ids_in.in(), mySourceMode->checkedId() == NodesSrc ? SMESH::NODE : SMESH::FACE ); + srcList->length( 1 ); + srcList[0] = s; + } + } + } + else { + srcList->length( mySrc.count() ); + for( int i = 0; i < mySrc.count(); i++ ) + srcList[i] = mySrc[i]; + } + if ( srcList->length() > 0 ) { + // compute bounding box + int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); + SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements(); + SMESH::Measure result = measure->BoundingBox( srcList.in() ); + measure->Destroy(); + myXmin->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myXmax->setText( QString::number( result.maxX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myDX->setText( QString::number( result.maxX-result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myYmin->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myYmax->setText( QString::number( result.maxY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myDY->setText( QString::number( result.maxY-result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myZmin->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myZmax->setText( QString::number( result.maxZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + myDZ->setText( QString::number( result.maxZ-result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + // update preview actor + erasePreview(); + createPreview( result.minX, result.maxX, result.minY, result.maxY, result.minZ, result.maxZ ); + displayPreview(); + } + else { + clear(); + } +} + +/*! + \brief Reset the widget to the initial state (nullify result fields) +*/ +void SMESHGUI_BoundingBox::clear() +{ + myXmin->clear(); + myXmax->clear(); + myDX->clear(); + myYmin->clear(); + myYmax->clear(); + myDY->clear(); + myZmin->clear(); + myZmax->clear(); + myDZ->clear(); + erasePreview(); +} + +/*! + \class SMESHGUI_MeshInfoDlg + \brief Centralized dialog box for the measurements +*/ + +/*! + \brief Constructor + \param parent parent widget + \param page specifies the dialog page to be shown at the start-up +*/ +SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page ) +: QDialog( parent ) +{ + setModal( false ); + setAttribute( Qt::WA_DeleteOnClose, true ); + setWindowTitle( tr( "MEASUREMENTS" ) ); + setSizeGripEnabled( true ); + + SUIT_ResourceMgr* resMgr = SMESHGUI::resourceMgr(); + + myTabWidget = new QTabWidget( this ); + + // min distance + + myMinDist = new SMESHGUI_MinDistance( myTabWidget ); + myTabWidget->addTab( myMinDist, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_MIN_DIST" ) ), tr( "MIN_DIST" ) ); + + // bounding box + + myBndBox = new SMESHGUI_BoundingBox( myTabWidget ); + myTabWidget->addTab( myBndBox, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BND_BOX" ) ), tr( "BND_BOX" ) ); + + // buttons + QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this ); + okBtn->setAutoDefault( true ); + okBtn->setDefault( true ); + okBtn->setFocus(); + QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this ); + helpBtn->setAutoDefault( true ); + + QHBoxLayout* btnLayout = new QHBoxLayout; + btnLayout->setSpacing( SPACING ); + btnLayout->setMargin( 0 ); + btnLayout->addWidget( okBtn ); + btnLayout->addStretch( 10 ); + btnLayout->addWidget( helpBtn ); + + QVBoxLayout* l = new QVBoxLayout ( this ); + l->setMargin( MARGIN ); + l->setSpacing( SPACING ); + l->addWidget( myTabWidget ); + l->addStretch(); + l->addLayout( btnLayout ); + + myTabWidget->setCurrentIndex( qMax( (int)MinDistance, qMin( (int)BoundingBox, page ) ) ); + + connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); + connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) ); + connect( myTabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( updateSelection() ) ); + connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) ); + connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) ); + + updateSelection(); +} + +/*! + \brief Destructor +*/ +SMESHGUI_MeasureDlg::~SMESHGUI_MeasureDlg() +{ +} + +/*! + \brief Perform clean-up actions on the dialog box closing. +*/ +void SMESHGUI_MeasureDlg::reject() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + selMgr->clearFilters(); + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( ActorSelection ); + QDialog::reject(); +} + +/*! + \brief Process keyboard event + \param e key press event +*/ +void SMESHGUI_MeasureDlg::keyPressEvent( QKeyEvent* e ) +{ + QDialog::keyPressEvent( e ); + if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) { + e->accept(); + help(); + } +} + +/*! + \brief Reactivate dialog box, when mouse pointer goes into it. +*/ +void SMESHGUI_MeasureDlg::enterEvent( QEvent* ) +{ + activate(); +} + +/*! + \brief Setup selection mode depending on the current dialog box state. +*/ +void SMESHGUI_MeasureDlg::updateSelection() +{ + if ( myTabWidget->currentIndex() == MinDistance ) + myMinDist->updateSelection(); + else if ( myTabWidget->currentIndex() == BoundingBox ) + myBndBox->updateSelection(); + +} + +/*! + \brief Show help page +*/ +void SMESHGUI_MeasureDlg::help() +{ + SMESH::ShowHelpFile( myTabWidget->currentIndex() == MinDistance ? + "measurements_page.html#min_distance_anchor" : + "measurements_page.html#bounding_box_anchor" ); +} + +/*! + \brief Activate dialog box +*/ +void SMESHGUI_MeasureDlg::activate() +{ + SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog(); + SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this ); + myTabWidget->setEnabled( true ); + updateSelection(); +} + +/*! + \brief Deactivate dialog box +*/ +void SMESHGUI_MeasureDlg::deactivate() +{ + myMinDist->deactivate(); + myBndBox->deactivate(); + myTabWidget->setEnabled( false ); + disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) ); +} diff --git a/src/SMESHGUI/SMESHGUI_Measurements.h b/src/SMESHGUI/SMESHGUI_Measurements.h new file mode 100644 index 000000000..b9b58c8be --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_Measurements.h @@ -0,0 +1,172 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SMESHGUI_Measurements.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) + +#ifndef SMESHGUI_MEASUREMENTS_H +#define SMESHGUI_MEASUREMENTS_H + +#include "SMESH_SMESHGUI.hxx" + +#include + +class QButtonGroup; +class QLineEdit; +class QTabWidget; +class SUIT_SelectionFilter; +class SALOME_Actor; +class SMESH_Actor; +class SMESHGUI_IdValidator; + +#include +#include CORBA_SERVER_HEADER(SMESH_Mesh) + +class SMESHGUI_EXPORT SMESHGUI_MinDistance : public QWidget +{ + Q_OBJECT; + + enum { NoTgt, FirstTgt, SecondTgt }; + enum { OriginTgt, NodeTgt, ElementTgt, ObjectTgt }; + +public: + SMESHGUI_MinDistance( QWidget* = 0 ); + ~SMESHGUI_MinDistance(); + + bool eventFilter( QObject*, QEvent* ); + void updateSelection(); + void deactivate(); + +private: + void setTarget( int ); + void erasePreview(); + void displayPreview(); + void createPreview( double, double, double, double, double, double ); + +private slots: + void selectionChanged(); + void firstChanged(); + void secondChanged(); + void firstEdited(); + void secondEdited(); + void compute(); + void clear(); + +private: + QButtonGroup* myFirst; + QButtonGroup* mySecond; + QLineEdit* myFirstTgt; + QLineEdit* mySecondTgt; + QLineEdit* myDX; + QLineEdit* myDY; + QLineEdit* myDZ; + QLineEdit* myDistance; + int myCurrentTgt; + SMESH::SMESH_IDSource_var myFirstSrc; + SMESH::SMESH_IDSource_var mySecondSrc; + SMESH_Actor* myFirstActor; + SMESH_Actor* mySecondActor; + SMESHGUI_IdValidator* myValidator; + SUIT_SelectionFilter* myFilter; + SALOME_Actor* myPreview; +}; + +class SMESHGUI_EXPORT SMESHGUI_BoundingBox : public QWidget +{ + Q_OBJECT; + + enum { ObjectsSrc, NodesSrc, ElementsSrc }; + +public: + SMESHGUI_BoundingBox( QWidget* = 0 ); + ~SMESHGUI_BoundingBox(); + + void updateSelection(); + void deactivate(); + +private: + void erasePreview(); + void displayPreview(); + void createPreview( double, double, double, double, double, double ); + +private slots: + void selectionChanged(); + void sourceChanged(); + void sourceEdited(); + void compute(); + void clear(); + +private: + typedef QList SourceList; + QButtonGroup* mySourceMode; + QLineEdit* mySource; + QLineEdit* myXmin; + QLineEdit* myXmax; + QLineEdit* myDX; + QLineEdit* myYmin; + QLineEdit* myYmax; + QLineEdit* myDY; + QLineEdit* myZmin; + QLineEdit* myZmax; + QLineEdit* myDZ; + SourceList mySrc; + SMESH_Actor* myActor; + SMESHGUI_IdValidator* myValidator; + QString myIDs; + SUIT_SelectionFilter* myFilter; + SALOME_Actor* myPreview; +}; + +class SMESHGUI_EXPORT SMESHGUI_MeasureDlg : public QDialog +{ + Q_OBJECT; + + enum { NodeMode, ElemMode }; + +public: + //! Measurement type + enum { + MinDistance, //!< minimum distance + BoundingBox //!< bounding box + }; + + SMESHGUI_MeasureDlg( QWidget* = 0, int = MinDistance ); + ~SMESHGUI_MeasureDlg(); + + void reject(); + +protected: + void keyPressEvent( QKeyEvent* ); + void enterEvent( QEvent* ); + +private slots: + void help(); + void updateSelection(); + void activate(); + void deactivate(); + +private: + QTabWidget* myTabWidget; + SMESHGUI_MinDistance* myMinDist; + SMESHGUI_BoundingBox* myBndBox; +}; + +#endif // SMESHGUI_MEASUREMENTS_H diff --git a/src/SMESHGUI/SMESHGUI_EditMeshDlg.cxx b/src/SMESHGUI/SMESHGUI_MergeDlg.cxx similarity index 90% rename from src/SMESHGUI/SMESHGUI_EditMeshDlg.cxx rename to src/SMESHGUI/SMESHGUI_MergeDlg.cxx index 64559a58a..26922e93d 100644 --- a/src/SMESHGUI/SMESHGUI_EditMeshDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MergeDlg.cxx @@ -21,11 +21,11 @@ // // SMESH SMESHGUI : GUI for SMESH component -// File : SMESHGUI_EditMeshDlg.cxx +// File : SMESHGUI_MergeDlg.cxx // Author : Open CASCADE S.A.S. // SMESH includes // -#include "SMESHGUI_EditMeshDlg.h" +#include "SMESHGUI_MergeDlg.h" #include "SMESHGUI.h" #include "SMESHGUI_Utils.h" @@ -303,11 +303,10 @@ static const char * IconFirst[] = { " . . "}; //================================================================================= -// class : SMESHGUI_EditMeshDlg() +// class : SMESHGUI_MergeDlg() // purpose : //================================================================================= -SMESHGUI_EditMeshDlg::SMESHGUI_EditMeshDlg (SMESHGUI* theModule, - int theAction) +SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction) : QDialog(SMESH::GetDesktop(theModule)), mySMESHGUI(theModule), mySelectionMgr(SMESH::GetSelectionMgr(theModule)), @@ -392,29 +391,43 @@ SMESHGUI_EditMeshDlg::SMESHGUI_EditMeshDlg (SMESHGUI* theModule, this); QVBoxLayout* aCoincidentLayout = new QVBoxLayout(GroupCoincident); + aCoincidentLayout->setSpacing(SPACING); + aCoincidentLayout->setMargin(MARGIN); - GroupCoincident->setLayout(aCoincidentLayout); - - QHBoxLayout* aSpinBoxLayout = new QHBoxLayout( GroupCoincident ); - if (myAction == 0) { // case merge nodes - TextLabelTolerance = new QLabel(tr("SMESH_TOLERANCE"), GroupCoincident); - SpinBoxTolerance = new SMESHGUI_SpinBox(GroupCoincident); + QWidget* foo = new QWidget(GroupCoincident); + TextLabelTolerance = new QLabel(tr("SMESH_TOLERANCE"), foo); + SpinBoxTolerance = new SMESHGUI_SpinBox(foo); SpinBoxTolerance->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); - aSpinBoxLayout->addWidget(TextLabelTolerance); - aSpinBoxLayout->addWidget(SpinBoxTolerance); - aCoincidentLayout->addLayout(aSpinBoxLayout); + GroupExclude = new QGroupBox(tr("EXCLUDE_GROUPS"), foo); + GroupExclude->setCheckable( true ); + GroupExclude->setChecked( false ); + ListExclude = new QListWidget( GroupExclude ); + QVBoxLayout* GroupExcludeLayout = new QVBoxLayout(GroupExclude); + GroupExcludeLayout->setSpacing(SPACING); + GroupExcludeLayout->setMargin(MARGIN); + GroupExcludeLayout->addWidget(ListExclude); + + QGridLayout* fooLayout = new QGridLayout( foo ); + fooLayout->setSpacing(SPACING); + fooLayout->setMargin(0); + fooLayout->addWidget(TextLabelTolerance, 0, 0 ); + fooLayout->addWidget(SpinBoxTolerance, 0, 1 ); + fooLayout->addWidget(GroupExclude, 1, 0, 1, 2 ); + aCoincidentLayout->addWidget(foo); } else { TextLabelTolerance = 0; SpinBoxTolerance = 0; + GroupExclude = 0; + ListExclude = 0; } GroupCoincidentWidget = new QWidget(GroupCoincident); QGridLayout* GroupCoincidentLayout = new QGridLayout(GroupCoincidentWidget); GroupCoincidentLayout->setSpacing(SPACING); - GroupCoincidentLayout->setMargin(MARGIN); + GroupCoincidentLayout->setMargin(0); ListCoincident = new QListWidget(GroupCoincidentWidget); ListCoincident->setSelectionMode(QListWidget::ExtendedSelection); @@ -425,11 +438,6 @@ SMESHGUI_EditMeshDlg::SMESHGUI_EditMeshDlg (SMESHGUI* theModule, SelectAllCB = new QCheckBox(tr("SELECT_ALL"), GroupCoincidentWidget); - if (myAction == 0) - GroupCoincidentWidget->hide(); - else - GroupCoincident->hide(); - GroupCoincidentLayout->addWidget(ListCoincident, 0, 0, 4, 2); GroupCoincidentLayout->addWidget(DetectButton, 0, 2); GroupCoincidentLayout->addWidget(AddGroupButton, 2, 2); @@ -466,8 +474,6 @@ SMESHGUI_EditMeshDlg::SMESHGUI_EditMeshDlg (SMESHGUI* theModule, GroupEditLayout->addWidget(RemoveElemButton, 0, 2); GroupEditLayout->addWidget(SetFirstButton, 1, 1, 1, 2); - GroupEdit->hide(); - /***************************************************************/ GroupButtons = new QGroupBox(this); QHBoxLayout* GroupButtonsLayout = new QHBoxLayout(GroupButtons); @@ -500,16 +506,21 @@ SMESHGUI_EditMeshDlg::SMESHGUI_EditMeshDlg (SMESHGUI* theModule, DlgLayout->addWidget(GroupEdit); DlgLayout->addWidget(GroupButtons); + GroupCoincidentWidget->setVisible( myAction != 0 ); + GroupCoincident->setVisible( myAction == 0 ); + //if GroupExclude->setVisible( myAction == 0 ); + GroupEdit->hide(); + this->resize(10,10); Init(); // Initialisations } //================================================================================= -// function : ~SMESHGUI_EditMeshDlg() +// function : ~SMESHGUI_MergeDlg() // purpose : Destroys the object and frees any allocated resources //================================================================================= -SMESHGUI_EditMeshDlg::~SMESHGUI_EditMeshDlg() +SMESHGUI_MergeDlg::~SMESHGUI_MergeDlg() { delete myIdPreview; } @@ -518,7 +529,7 @@ SMESHGUI_EditMeshDlg::~SMESHGUI_EditMeshDlg() // function : Init() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::Init() +void SMESHGUI_MergeDlg::Init() { if (myAction == 0) { SpinBoxTolerance->RangeStepAndValidator(0.0, COORD_MAX, 0.00001, "len_tol_precision"); @@ -578,8 +589,8 @@ void SMESHGUI_EditMeshDlg::Init() // function : FindGravityCenter() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::FindGravityCenter(TColStd_MapOfInteger & theElemsIdMap, - std::list< gp_XYZ > & theGrCentersXYZ) +void SMESHGUI_MergeDlg::FindGravityCenter(TColStd_MapOfInteger & theElemsIdMap, + std::list< gp_XYZ > & theGrCentersXYZ) { if (!myActor) return; @@ -613,7 +624,7 @@ void SMESHGUI_EditMeshDlg::FindGravityCenter(TColStd_MapOfInteger & theElemsIdMa // function : ClickOnApply() // purpose : //================================================================================= -bool SMESHGUI_EditMeshDlg::ClickOnApply() +bool SMESHGUI_MergeDlg::ClickOnApply() { if (mySMESHGUI->isActiveStudyLocked() || myMesh->_is_nil()) return false; @@ -681,7 +692,7 @@ bool SMESHGUI_EditMeshDlg::ClickOnApply() // function : ClickOnOk() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::ClickOnOk() +void SMESHGUI_MergeDlg::ClickOnOk() { if (ClickOnApply()) ClickOnCancel(); @@ -691,7 +702,7 @@ void SMESHGUI_EditMeshDlg::ClickOnOk() // function : ClickOnCancel() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::ClickOnCancel() +void SMESHGUI_MergeDlg::ClickOnCancel() { myIdPreview->SetPointsLabeled(false); SMESH::SetPointRepresentation(false); @@ -712,7 +723,7 @@ void SMESHGUI_EditMeshDlg::ClickOnCancel() // function : ClickOnHelp() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::ClickOnHelp() +void SMESHGUI_MergeDlg::ClickOnHelp() { LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication()); if (app) @@ -736,7 +747,7 @@ void SMESHGUI_EditMeshDlg::ClickOnHelp() // function : onEditGroup() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::onEditGroup() +void SMESHGUI_MergeDlg::onEditGroup() { QList selItems = ListCoincident->selectedItems(); if ( selItems.count() != 1 ) { @@ -758,7 +769,7 @@ void SMESHGUI_EditMeshDlg::onEditGroup() // function : updateControls() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::updateControls() +void SMESHGUI_MergeDlg::updateControls() { if (ListEdit->count() == 0) SetFirstButton->setEnabled(false); @@ -771,7 +782,7 @@ void SMESHGUI_EditMeshDlg::updateControls() // function : onDetect() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::onDetect() +void SMESHGUI_MergeDlg::onDetect() { if ( myMesh->_is_nil() || LineEditMesh->text().isEmpty() ) return; @@ -784,19 +795,27 @@ void SMESHGUI_EditMeshDlg::onDetect() ListEdit->clear(); SMESH::array_of_long_array_var aGroupsArray; + SMESH::ListOfIDSources_var aExcludeGroups = new SMESH::ListOfIDSources; + + SMESH::SMESH_IDSource_var src; + if ( mySubMeshOrGroup->_is_nil() ) src = SMESH::SMESH_IDSource::_duplicate( myMesh ); + else src = SMESH::SMESH_IDSource::_duplicate( mySubMeshOrGroup ); switch (myAction) { case 0 : - if(!mySubMeshOrGroup->_is_nil()) - aMeshEditor->FindCoincidentNodesOnPart(mySubMeshOrGroup, SpinBoxTolerance->GetValue(), aGroupsArray); - else - aMeshEditor->FindCoincidentNodes(SpinBoxTolerance->GetValue(), aGroupsArray); + for ( int i = 0; GroupExclude->isChecked() && i < ListExclude->count(); i++ ) { + if ( ListExclude->item( i )->checkState() == Qt::Checked ) { + aExcludeGroups->length( aExcludeGroups->length()+1 ); + aExcludeGroups[ aExcludeGroups->length()-1 ] = SMESH::SMESH_IDSource::_duplicate( myGroups[i] ); + } + } + aMeshEditor->FindCoincidentNodesOnPartBut(src.in(), + SpinBoxTolerance->GetValue(), + aGroupsArray.out(), + aExcludeGroups.in()); break; case 1 : - if(!mySubMeshOrGroup->_is_nil()) - aMeshEditor->FindEqualElements(mySubMeshOrGroup, aGroupsArray); - else - aMeshEditor->FindEqualElements(myMesh, aGroupsArray); + aMeshEditor->FindEqualElements(src.in(), aGroupsArray.out()); break; } @@ -820,7 +839,7 @@ void SMESHGUI_EditMeshDlg::onDetect() // function : onSelectGroup() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::onSelectGroup() +void SMESHGUI_MergeDlg::onSelectGroup() { if (myIsBusy || !myActor) return; @@ -869,7 +888,7 @@ void SMESHGUI_EditMeshDlg::onSelectGroup() // function : onSelectAll() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::onSelectAll (bool isToggled) +void SMESHGUI_MergeDlg::onSelectAll (bool isToggled) { if ( isToggled ) ListCoincident->selectAll(); @@ -881,7 +900,7 @@ void SMESHGUI_EditMeshDlg::onSelectAll (bool isToggled) // function : onSelectElementFromGroup() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::onSelectElementFromGroup() +void SMESHGUI_MergeDlg::onSelectElementFromGroup() { if (myIsBusy || !myActor) return; @@ -916,7 +935,7 @@ void SMESHGUI_EditMeshDlg::onSelectElementFromGroup() // function : onAddGroup() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::onAddGroup() +void SMESHGUI_MergeDlg::onAddGroup() { if ( myMesh->_is_nil() || LineEditMesh->text().isEmpty() ) return; @@ -948,7 +967,7 @@ void SMESHGUI_EditMeshDlg::onAddGroup() // function : onRemoveGroup() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::onRemoveGroup() +void SMESHGUI_MergeDlg::onRemoveGroup() { if (myEditCurrentArgument != (QWidget*)ListCoincident) return; @@ -970,7 +989,7 @@ void SMESHGUI_EditMeshDlg::onRemoveGroup() // function : onAddElement() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::onAddElement() +void SMESHGUI_MergeDlg::onAddElement() { if (!myActor) return; @@ -1006,7 +1025,7 @@ void SMESHGUI_EditMeshDlg::onAddElement() // function : onRemoveElement() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::onRemoveElement() +void SMESHGUI_MergeDlg::onRemoveElement() { if (myEditCurrentArgument != (QWidget*)ListCoincident) return; @@ -1026,7 +1045,7 @@ void SMESHGUI_EditMeshDlg::onRemoveElement() // function : onSetFirst() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::onSetFirst() +void SMESHGUI_MergeDlg::onSetFirst() { if (myEditCurrentArgument != (QWidget*)ListCoincident) return; @@ -1048,7 +1067,7 @@ void SMESHGUI_EditMeshDlg::onSetFirst() // function : SetEditCurrentArgument() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::SetEditCurrentArgument() +void SMESHGUI_MergeDlg::SetEditCurrentArgument() { QPushButton* send = (QPushButton*)sender(); @@ -1074,7 +1093,7 @@ void SMESHGUI_EditMeshDlg::SetEditCurrentArgument() // function : SelectionIntoArgument() // purpose : Called when selection as changed or other case //================================================================================= -void SMESHGUI_EditMeshDlg::SelectionIntoArgument() +void SMESHGUI_MergeDlg::SelectionIntoArgument() { if (myEditCurrentArgument == (QWidget*)LineEditMesh) { QString aString = ""; @@ -1083,6 +1102,7 @@ void SMESHGUI_EditMeshDlg::SelectionIntoArgument() ListCoincident->clear(); ListEdit->clear(); myActor = 0; + QString aCurrentEntry = myEntry; int nbSel = SMESH::GetNameOfSelectedIObjects(mySelectionMgr, aString); if (nbSel != 1) { @@ -1098,6 +1118,7 @@ void SMESHGUI_EditMeshDlg::SelectionIntoArgument() mySelectionMgr->selectedObjects(aList); Handle(SALOME_InteractiveObject) IO = aList.First(); + myEntry = IO->getEntry(); myMesh = SMESH::GetMeshByIO(IO); if (myMesh->_is_nil()) @@ -1128,6 +1149,26 @@ void SMESHGUI_EditMeshDlg::SelectionIntoArgument() aViewWindow->SetSelectionMode(CellSelection); } + // process groups + if ( myAction == 0 && !myMesh->_is_nil() && myEntry != aCurrentEntry ) { + myGroups.clear(); + ListExclude->clear(); + SMESH::ListOfGroups_var aListOfGroups = myMesh->GetGroups(); + for( int i = 0, n = aListOfGroups->length(); i < n; i++ ) { + SMESH::SMESH_GroupBase_var aGroup = aListOfGroups[i]; + if ( !aGroup->_is_nil() ) { // && aGroup->GetType() == SMESH::NODE + QString aGroupName( aGroup->GetName() ); + if ( !aGroupName.isEmpty() ) { + myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroup)); + QListWidgetItem* item = new QListWidgetItem( aGroupName ); + item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable ); + item->setCheckState( Qt::Unchecked ); + ListExclude->addItem( item ); + } + } + } + } + updateControls(); } } @@ -1136,7 +1177,7 @@ void SMESHGUI_EditMeshDlg::SelectionIntoArgument() // function : DeactivateActiveDialog() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::DeactivateActiveDialog() +void SMESHGUI_MergeDlg::DeactivateActiveDialog() { if (GroupConstructors->isEnabled()) { GroupConstructors->setEnabled(false); @@ -1157,7 +1198,7 @@ void SMESHGUI_EditMeshDlg::DeactivateActiveDialog() // function : ActivateThisDialog() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::ActivateThisDialog() +void SMESHGUI_MergeDlg::ActivateThisDialog() { /* Emit a signal to deactivate the active dialog */ mySMESHGUI->EmitSignalDeactivateDialog(); @@ -1177,7 +1218,7 @@ void SMESHGUI_EditMeshDlg::ActivateThisDialog() // function : enterEvent() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::enterEvent(QEvent*) +void SMESHGUI_MergeDlg::enterEvent(QEvent*) { if (!GroupConstructors->isEnabled()) ActivateThisDialog(); @@ -1187,7 +1228,7 @@ void SMESHGUI_EditMeshDlg::enterEvent(QEvent*) // function : closeEvent() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::closeEvent(QCloseEvent*) +void SMESHGUI_MergeDlg::closeEvent(QCloseEvent*) { /* same than click on cancel button */ ClickOnCancel(); @@ -1197,7 +1238,7 @@ void SMESHGUI_EditMeshDlg::closeEvent(QCloseEvent*) //function : hideEvent //purpose : caused by ESC key //======================================================================= -void SMESHGUI_EditMeshDlg::hideEvent (QHideEvent *) +void SMESHGUI_MergeDlg::hideEvent (QHideEvent *) { if (!isMinimized()) ClickOnCancel(); @@ -1207,7 +1248,7 @@ void SMESHGUI_EditMeshDlg::hideEvent (QHideEvent *) // function : keyPressEvent() // purpose : //================================================================================= -void SMESHGUI_EditMeshDlg::keyPressEvent( QKeyEvent* e) +void SMESHGUI_MergeDlg::keyPressEvent( QKeyEvent* e) { QDialog::keyPressEvent( e ); if ( e->isAccepted() ) @@ -1223,14 +1264,15 @@ void SMESHGUI_EditMeshDlg::keyPressEvent( QKeyEvent* e) // function : onTypeChanged() // purpose : the type radio button management //================================================================================= -void SMESHGUI_EditMeshDlg::onTypeChanged (int id) +void SMESHGUI_MergeDlg::onTypeChanged (int id) { if (myTypeId == id) return; myTypeId = id; - switch (id) { - case 0: + switch (id) + { + case 0: // automatic myIdPreview->SetPointsLabeled(false); SMESH::SetPointRepresentation(false); if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) @@ -1242,7 +1284,8 @@ void SMESHGUI_EditMeshDlg::onTypeChanged (int id) GroupCoincident->hide(); GroupEdit->hide(); break; - case 1: + + case 1: // manual SMESH::UpdateView(); // Costruction of the logical filter diff --git a/src/SMESHGUI/SMESHGUI_EditMeshDlg.h b/src/SMESHGUI/SMESHGUI_MergeDlg.h similarity index 91% rename from src/SMESHGUI/SMESHGUI_EditMeshDlg.h rename to src/SMESHGUI/SMESHGUI_MergeDlg.h index 4ff701452..73dce16c0 100644 --- a/src/SMESHGUI/SMESHGUI_EditMeshDlg.h +++ b/src/SMESHGUI/SMESHGUI_MergeDlg.h @@ -21,11 +21,11 @@ // // SMESH SMESHGUI : GUI for SMESH component -// File : SMESHGUI_EditMeshDlg.h +// File : SMESHGUI_MergeDlg.h // Author : Open CASCADE S.A.S. // -#ifndef SMESHGUI_EDITMESHDLG_H -#define SMESHGUI_EDITMESHDLG_H +#ifndef SMESHGUI_MergeDlg_H +#define SMESHGUI_MergeDlg_H // SMESH includes #include "SMESH_SMESHGUI.hxx" @@ -65,16 +65,16 @@ namespace SMESH } //================================================================================= -// class : SMESHGUI_EditMeshDlg +// class : SMESHGUI_MergeDlg // purpose : //================================================================================= -class SMESHGUI_EXPORT SMESHGUI_EditMeshDlg : public QDialog +class SMESHGUI_EXPORT SMESHGUI_MergeDlg : public QDialog { Q_OBJECT; public: - SMESHGUI_EditMeshDlg( SMESHGUI*, int ); - ~SMESHGUI_EditMeshDlg(); + SMESHGUI_MergeDlg( SMESHGUI*, int ); + ~SMESHGUI_MergeDlg(); private: void Init(); @@ -89,6 +89,8 @@ private: // add the centers of gravity of ElemsIdMap elements to the GrCentersXYZ list private: + typedef QList GrpList; + SMESHGUI* mySMESHGUI; /* Current SMESHGUI object */ LightApp_SelectionMgr* mySelectionMgr; /* User shape selection */ SVTK_Selector* mySelector; @@ -137,11 +139,17 @@ private: QPushButton* RemoveElemButton; QPushButton* SetFirstButton; + QGroupBox* GroupExclude; + QListWidget* ListExclude; + QGroupBox* TypeBox; QButtonGroup* GroupType; QString myHelpFileName; + QString myEntry; + GrpList myGroups; + private slots: void ClickOnOk(); void ClickOnCancel(); @@ -164,4 +172,4 @@ private: void onTypeChanged(int); }; -#endif // SMESHGUI_EDITMESHDLG_H +#endif // SMESHGUI_MergeDlg_H diff --git a/src/SMESHGUI/SMESHGUI_MeshInfo.cxx b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx new file mode 100644 index 000000000..16a33b199 --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx @@ -0,0 +1,1335 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SMESHGUI_MeshInfo.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) + +#include "SMESHGUI_MeshInfo.h" + +#include "SMESH_Actor.h" +#include "SMESHGUI.h" +#include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_Utils.h" +#include "SMESHGUI_VTKUtils.h" +#include "SMDSAbs_ElementType.hxx" +#include "SMDS_Mesh.hxx" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include CORBA_SERVER_HEADER(SMESH_Group) + +const int SPACING = 6; +const int MARGIN = 9; + +/*! + \class SMESHGUI_MeshInfo + \brief Base mesh information widget + + Displays the base information about mesh object: mesh, sub-mesh, group or arbitrary ID source. +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent ) + : QFrame( parent ), myWidgets( iElementsEnd ) +{ + setFrameStyle( StyledPanel | Sunken ); + + QGridLayout* l = new QGridLayout( this ); + l->setMargin( MARGIN ); + l->setSpacing( SPACING ); + + // object + QLabel* aNameLab = new QLabel( tr( "NAME_LAB" ), this ); + QLabel* aName = createField(); + aName->setMinimumWidth( 150 ); + QLabel* aObjLab = new QLabel( tr( "OBJECT_LAB" ), this ); + QLabel* aObj = createField(); + aObj->setMinimumWidth( 150 ); + myWidgets[0] << aNameLab << aName; + myWidgets[1] << aObjLab << aObj; + + // nodes + QWidget* aNodesLine = createLine(); + QLabel* aNodesLab = new QLabel( tr( "NODES_LAB" ), this ); + QLabel* aNodes = createField(); + myWidgets[2] << aNodesLine; + myWidgets[3] << aNodesLab << aNodes; + + // elements + QWidget* aElemLine = createLine(); + QLabel* aElemLab = new QLabel( tr( "ELEMENTS_LAB" ), this ); + QLabel* aElemTotal = new QLabel( tr( "TOTAL_LAB" ), this ); + QLabel* aElemLin = new QLabel( tr( "LINEAR_LAB" ), this ); + QLabel* aElemQuad = new QLabel( tr( "QUADRATIC_LAB" ), this ); + myWidgets[4] << aElemLine; + myWidgets[5] << aElemLab << aElemTotal << aElemLin << aElemQuad; + + // ... 0D elements + QWidget* a0DLine = createLine(); + QLabel* a0DLab = new QLabel( tr( "0D_LAB" ), this ); + QLabel* a0DTotal = createField(); + myWidgets[6] << a0DLine; + myWidgets[7] << a0DLab << a0DTotal; + + // ... 1D elements + QWidget* a1DLine = createLine(); + QLabel* a1DLab = new QLabel( tr( "1D_LAB" ), this ); + QLabel* a1DTotal = createField(); + QLabel* a1DLin = createField(); + QLabel* a1DQuad = createField(); + myWidgets[8] << a1DLine; + myWidgets[9] << a1DLab << a1DTotal << a1DLin << a1DQuad; + + // ... 2D elements + QWidget* a2DLine = createLine(); + QLabel* a2DLab = new QLabel( tr( "2D_LAB" ), this ); + QLabel* a2DTotal = createField(); + QLabel* a2DLin = createField(); + QLabel* a2DQuad = createField(); + QLabel* a2DTriLab = new QLabel( tr( "TRIANGLES_LAB" ), this ); + QLabel* a2DTriTotal = createField(); + QLabel* a2DTriLin = createField(); + QLabel* a2DTriQuad = createField(); + QLabel* a2DQuaLab = new QLabel( tr( "QUADRANGLES_LAB" ), this ); + QLabel* a2DQuaTotal = createField(); + QLabel* a2DQuaLin = createField(); + QLabel* a2DQuaQuad = createField(); + QLabel* a2DPolLab = new QLabel( tr( "POLYGONS_LAB" ), this ); + QLabel* a2DPolTotal = createField(); + myWidgets[10] << a2DLine; + myWidgets[11] << a2DLab << a2DTotal << a2DLin << a2DQuad; + myWidgets[12] << a2DTriLab << a2DTriTotal << a2DTriLin << a2DTriQuad; + myWidgets[13] << a2DQuaLab << a2DQuaTotal << a2DQuaLin << a2DQuaQuad; + myWidgets[14] << a2DPolLab << a2DPolTotal; + + // ... 3D elements + QWidget* a3DLine = createLine(); + QLabel* a3DLab = new QLabel( tr( "3D_LAB" ), this ); + QLabel* a3DTotal = createField(); + QLabel* a3DLin = createField(); + QLabel* a3DQuad = createField(); + QLabel* a3DTetLab = new QLabel( tr( "TETRAHEDRONS_LAB" ), this ); + QLabel* a3DTetTotal = createField(); + QLabel* a3DTetLin = createField(); + QLabel* a3DTetQuad = createField(); + QLabel* a3DHexLab = new QLabel( tr( "HEXAHEDONRS_LAB" ), this ); + QLabel* a3DHexTotal = createField(); + QLabel* a3DHexLin = createField(); + QLabel* a3DHexQuad = createField(); + QLabel* a3DPyrLab = new QLabel( tr( "PYRAMIDS_LAB" ), this ); + QLabel* a3DPyrTotal = createField(); + QLabel* a3DPyrLin = createField(); + QLabel* a3DPyrQuad = createField(); + QLabel* a3DPriLab = new QLabel( tr( "PRISMS_LAB" ), this ); + QLabel* a3DPriTotal = createField(); + QLabel* a3DPriLin = createField(); + QLabel* a3DPriQuad = createField(); + QLabel* a3DPolLab = new QLabel( tr( "POLYHEDRONS_LAB" ), this ); + QLabel* a3DPolTotal = createField(); + myWidgets[15] << a3DLine; + myWidgets[16] << a3DLab << a3DTotal << a3DLin << a3DQuad; + myWidgets[17] << a3DTetLab << a3DTetTotal << a3DTetLin << a3DTetQuad; + myWidgets[18] << a3DHexLab << a3DHexTotal << a3DHexLin << a3DHexQuad; + myWidgets[19] << a3DPyrLab << a3DPyrTotal << a3DPyrLin << a3DPyrQuad; + myWidgets[20] << a3DPriLab << a3DPriTotal << a3DPriLin << a3DPriQuad; + myWidgets[21] << a3DPolLab << a3DPolTotal; + + setFontAttributes( aNameLab, Bold ); + setFontAttributes( aObjLab, Bold ); + setFontAttributes( aNodesLab, Bold ); + setFontAttributes( aElemLab, Bold ); + setFontAttributes( aElemTotal, Italic ); + setFontAttributes( aElemLin, Italic ); + setFontAttributes( aElemQuad, Italic ); + setFontAttributes( a0DLab, Bold ); + setFontAttributes( a1DLab, Bold ); + setFontAttributes( a2DLab, Bold ); + setFontAttributes( a3DLab, Bold ); + + l->addWidget( aNameLab, 0, 0 ); + l->addWidget( aName, 0, 1, 1, 3 ); + l->addWidget( aObjLab, 1, 0 ); + l->addWidget( aObj, 1, 1, 1, 3 ); + l->addWidget( aNodesLine, 2, 0, 1, 4 ); + l->addWidget( aNodesLab, 3, 0 ); + l->addWidget( aNodes, 3, 1 ); + l->addWidget( aElemLine, 4, 0, 1, 4 ); + l->addWidget( aElemLab, 5, 0 ); + 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( a1DLine, 8, 1, 1, 3 ); + l->addWidget( a1DLab, 9, 0 ); + l->addWidget( a1DTotal, 9, 1 ); + l->addWidget( a1DLin, 9, 2 ); + l->addWidget( a1DQuad, 9, 3 ); + l->addWidget( a2DLine, 10, 1, 1, 3 ); + l->addWidget( a2DLab, 11, 0 ); + l->addWidget( a2DTotal, 11, 1 ); + l->addWidget( a2DLin, 11, 2 ); + l->addWidget( a2DQuad, 11, 3 ); + l->addWidget( a2DTriLab, 12, 0 ); + l->addWidget( a2DTriTotal, 12, 1 ); + l->addWidget( a2DTriLin, 12, 2 ); + l->addWidget( a2DTriQuad, 12, 3 ); + l->addWidget( a2DQuaLab, 13, 0 ); + l->addWidget( a2DQuaTotal, 13, 1 ); + l->addWidget( a2DQuaLin, 13, 2 ); + l->addWidget( a2DQuaQuad, 13, 3 ); + l->addWidget( a2DPolLab, 14, 0 ); + l->addWidget( a2DPolTotal, 14, 1 ); + l->addWidget( a3DLine, 15, 1, 1, 3 ); + l->addWidget( a3DLab, 16, 0 ); + l->addWidget( a3DTotal, 16, 1 ); + l->addWidget( a3DLin, 16, 2 ); + l->addWidget( a3DQuad, 16, 3 ); + l->addWidget( a3DTetLab, 17, 0 ); + l->addWidget( a3DTetTotal, 17, 1 ); + l->addWidget( a3DTetLin, 17, 2 ); + l->addWidget( a3DTetQuad, 17, 3 ); + l->addWidget( a3DHexLab, 18, 0 ); + l->addWidget( a3DHexTotal, 18, 1 ); + l->addWidget( a3DHexLin, 18, 2 ); + l->addWidget( a3DHexQuad, 18, 3 ); + l->addWidget( a3DPyrLab, 19, 0 ); + l->addWidget( a3DPyrTotal, 19, 1 ); + l->addWidget( a3DPyrLin, 19, 2 ); + l->addWidget( a3DPyrQuad, 19, 3 ); + l->addWidget( a3DPriLab, 20, 0 ); + l->addWidget( a3DPriTotal, 20, 1 ); + l->addWidget( a3DPriLin, 20, 2 ); + l->addWidget( a3DPriQuad, 20, 3 ); + l->addWidget( a3DPolLab, 21, 0 ); + l->addWidget( a3DPolTotal, 21, 1 ); + l->setColumnStretch( 0, 0 ); + l->setColumnStretch( 1, 5 ); + l->setColumnStretch( 2, 5 ); + l->setColumnStretch( 3, 5 ); + l->setRowStretch( 22, 5 ); + + clear(); +} + +/*! + \brief Destructor +*/ +SMESHGUI_MeshInfo::~SMESHGUI_MeshInfo() +{ +} + +/*! + \brief Show information on the mesh object. + \param obj object being processed (mesh, sub-mesh, group, ID source) +*/ +void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) +{ + clear(); + if ( !CORBA::is_nil( obj ) ) { + _PTR(SObject) sobj = ObjectToSObject( obj ); + if ( sobj ) + myWidgets[iName][iSingle]->setProperty( "text", sobj->GetName().c_str() ); + SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_narrow( obj ); + SMESH::SMESH_subMesh_var aSubMesh = SMESH::SMESH_subMesh::_narrow( obj ); + SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_narrow( obj ); + if ( !aMesh->_is_nil() ) { + myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_MESH" ) ); + } + else if ( !aSubMesh->_is_nil() ) { + myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_SUBMESH" ) ); + } + else if ( !aGroup->_is_nil() ) { + QString objType; + switch( aGroup->GetType() ) { + case SMESH::NODE: + objType = tr( "OBJECT_GROUP_NODES" ); + break; + case SMESH::EDGE: + objType = tr( "OBJECT_GROUP_EDGES" ); + break; + case SMESH::FACE: + objType = tr( "OBJECT_GROUP_FACES" ); + break; + case SMESH::VOLUME: + objType = tr( "OBJECT_GROUP_VOLUMES" ); + break; + case SMESH::ELEM0D: + objType = tr( "OBJECT_GROUP_0DELEMS" ); + break; + default: + objType = tr( "OBJECT_GROUP" ); + break; + } + myWidgets[iObject][iSingle]->setProperty( "text", objType ); + } + SMESH::long_array_var info = obj->GetMeshInfo(); + myWidgets[iNodes][iTotal]->setProperty( "text", QString::number( info[SMDSEntity_Node] ) ); + myWidgets[i0D][iTotal]->setProperty( "text", QString::number( info[SMDSEntity_0D] ) ); + long nbEdges = info[SMDSEntity_Edge] + info[SMDSEntity_Quad_Edge]; + myWidgets[i1D][iTotal]->setProperty( "text", QString::number( nbEdges ) ); + myWidgets[i1D][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Edge] ) ); + myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Edge] ) ); + long nbTriangles = info[SMDSEntity_Triangle] + info[SMDSEntity_Quad_Triangle]; + long nbQuadrangles = info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle]; + long nb2DLinear = info[SMDSEntity_Triangle] + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Polygon]; + long nb2DQuadratic = info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_Quad_Quadrangle]; + myWidgets[i2D][iTotal]->setProperty( "text", QString::number( nb2DLinear + nb2DQuadratic ) ); + myWidgets[i2D][iLinear]->setProperty( "text", QString::number( nb2DLinear ) ); + myWidgets[i2D][iQuadratic]->setProperty( "text", QString::number( nb2DQuadratic ) ); + myWidgets[i2DTriangles][iTotal]->setProperty( "text", QString::number( nbTriangles ) ); + myWidgets[i2DTriangles][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Triangle] ) ); + myWidgets[i2DTriangles][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Triangle] ) ); + myWidgets[i2DQuadrangles][iTotal]->setProperty( "text", QString::number( nbQuadrangles ) ); + myWidgets[i2DQuadrangles][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Quadrangle] ) ); + myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Quadrangle] ) ); + myWidgets[i2DPolygons][iTotal]->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ) ); + long nbTetrahedrons = info[SMDSEntity_Tetra] + info[SMDSEntity_Quad_Tetra]; + long nbHexahedrons = info[SMDSEntity_Hexa] + info[SMDSEntity_Quad_Hexa]; + long nbPyramids = info[SMDSEntity_Pyramid] + info[SMDSEntity_Quad_Pyramid]; + long nbPrisms = info[SMDSEntity_Penta] + info[SMDSEntity_Quad_Penta]; + long nb3DLinear = info[SMDSEntity_Tetra] + info[SMDSEntity_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Penta] + info[SMDSEntity_Polyhedra]; + long nb3DQuadratic = info[SMDSEntity_Quad_Tetra] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_Quad_Pyramid] + info[SMDSEntity_Quad_Penta]; + myWidgets[i3D][iTotal]->setProperty( "text", QString::number( nb3DLinear + nb3DQuadratic ) ); + myWidgets[i3D][iLinear]->setProperty( "text", QString::number( nb3DLinear ) ); + myWidgets[i3D][iQuadratic]->setProperty( "text", QString::number( nb3DQuadratic ) ); + myWidgets[i3DTetrahedrons][iTotal]->setProperty( "text", QString::number( nbTetrahedrons ) ); + myWidgets[i3DTetrahedrons][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Tetra] ) ); + myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Tetra] ) ); + myWidgets[i3DHexahedrons][iTotal]->setProperty( "text", QString::number( nbHexahedrons ) ); + myWidgets[i3DHexahedrons][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Hexa] ) ); + myWidgets[i3DHexahedrons][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Hexa] ) ); + myWidgets[i3DPyramids][iTotal]->setProperty( "text", QString::number( nbPyramids ) ); + myWidgets[i3DPyramids][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Pyramid] ) ); + myWidgets[i3DPyramids][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Pyramid] ) ); + myWidgets[i3DPrisms][iTotal]->setProperty( "text", QString::number( nbPrisms ) ); + myWidgets[i3DPrisms][iLinear]->setProperty( "text", QString::number( info[SMDSEntity_Penta] ) ); + myWidgets[i3DPrisms][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Penta] ) ); + myWidgets[i3DPolyhedrons][iTotal]->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ) ); + } +} + +/*! + \brief Reset the widget to the initial state (nullify all fields). +*/ +void SMESHGUI_MeshInfo::clear() +{ + myWidgets[iName][iSingle]->setProperty( "text", QString() ); + myWidgets[iObject][iSingle]->setProperty( "text", QString() ); + myWidgets[iNodes][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i0D][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i1D][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i1D][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2D][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2D][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2D][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DTriangles][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DTriangles][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DTriangles][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DQuadrangles][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DQuadrangles][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DPolygons][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3D][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3D][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3D][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DTetrahedrons][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DTetrahedrons][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DHexahedrons][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DHexahedrons][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DHexahedrons][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPyramids][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPyramids][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPyramids][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPrisms][iTotal]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPrisms][iLinear]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPrisms][iQuadratic]->setProperty( "text", QString::number( 0 ) ); + myWidgets[i3DPolyhedrons][iTotal]->setProperty( "text", QString::number( 0 ) ); +} + +/*! + \brief Create info field + \return new info field +*/ +QLabel* SMESHGUI_MeshInfo::createField() +{ + QLabel* lab = new QLabel( this ); + lab->setFrameStyle( StyledPanel | Sunken ); + lab->setAlignment( Qt::AlignCenter ); + lab->setAutoFillBackground( true ); + QPalette pal = lab->palette(); + pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) ); + lab->setPalette( pal ); + lab->setMinimumWidth( 70 ); + return lab; +} + +/*! + \brief Create horizontal rule. + \return new line object +*/ +QWidget* SMESHGUI_MeshInfo::createLine() +{ + QFrame* line = new QFrame( this ); + line->setFrameStyle( HLine | Sunken ); + return line; +} + +/*! + \brief Change widget font attributes (bold, italic, ...). + \param w widget + \param attr font attributes (XORed flags) + \param val value to be set to attributes +*/ +void SMESHGUI_MeshInfo::setFontAttributes( QWidget* w, int attr, bool val ) +{ + if ( w && attr ) { + QFont f = w->font(); + if ( attr & Bold ) f.setBold( val ); + if ( attr & Italic ) f.setItalic( val ); + w->setFont( f ); + } +} + +/*! + \brief Show/hide group(s) of fields. + \param start beginning of the block + \param end end of the block + \param on visibility flag +*/ +void SMESHGUI_MeshInfo::setFieldsVisible( int start, int end, bool on ) +{ + start = qMax( 0, start ); + end = qMin( end, (int)iElementsEnd ); + for ( int i = start; i < end; i++ ) { + wlist wl = myWidgets[i]; + foreach ( QWidget* w, wl ) w->setVisible( on ); + } +} + +/*! + \class SMESHGUI_ElemInfo + \brief Base class for the mesh element information widget. +*/ + +/*! + \brief Constructor + \param parent parent widget +*/ +SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent ) +: QWidget( parent ), myActor( 0 ), myID( 0 ), myIsElement( -1 ) +{ +} + +/*! + \brief Destructor +*/ +SMESHGUI_ElemInfo::~SMESHGUI_ElemInfo() +{ +} + +/*! + \brief Set mesh data source (actor) + \param actor mesh object actor +*/ +void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor ) +{ + if ( myActor != actor ) { + myActor = actor; + myID = 0; + myIsElement = -1; + clear(); + } +} + +/*! + \brief Show mesh element information + \param long id mesh node / element ID + \param isElem show mesh element information if \c true or mesh node information if \c false +*/ +void SMESHGUI_ElemInfo::showInfo( long id, bool isElem ) +{ + myID = id; + myIsElement = isElem; +} + +/*! + \fn void SMESHGUI_ElemInfo::clear() + \brief Clear mesh element information widget +*/ + +/*! + \brief Get node connectivity + \param node mesh node + \return node connectivity map +*/ +SMESHGUI_ElemInfo::Connectivity SMESHGUI_ElemInfo::nodeConnectivity( const SMDS_MeshNode* node ) +{ + Connectivity elmap; + if ( node ) { + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while ( it && it->more() ) { + const SMDS_MeshElement* ne = it->next(); + elmap[ ne->GetType() ] << ne->GetID(); + } + } + return elmap; +} + +/*! + \brief Format connectivity data to string representation + \param connectivity connetivity map + \param type element type + \return string representation of the connectivity +*/ +QString SMESHGUI_ElemInfo::formatConnectivity( Connectivity connectivity, int type ) +{ + QStringList str; + if ( connectivity.contains( type ) ) { + QList elements = connectivity[ type ]; + qSort( elements ); + foreach( int id, elements ) + str << QString::number( id ); + } + return str.join( " " ); +} + +/*! + \brief Calculate gravity center of the mesh element + \param element mesh element +*/ +SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::gravityCenter( const SMDS_MeshElement* element ) +{ + XYZ xyz; + if ( element ) { + SMDS_ElemIteratorPtr nodeIt = element->nodesIterator(); + while ( nodeIt->more() ) { + const SMDS_MeshNode* node = static_cast( nodeIt->next() ); + xyz.add( node->X(), node->Y(), node->Z() ); + } + xyz.divide( element->NbNodes() ); + } + return xyz; +} + +/*! + \class SMESHGUI_SimpleElemInfo + \brief Represents mesh element information in the simple text area. +*/ + +/*! + \brief Constructor + \param parent parent widget +*/ +SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent ) +: SMESHGUI_ElemInfo( parent ) +{ + myInfo = new QTextBrowser( this ); + QVBoxLayout* l = new QVBoxLayout( this ); + l->setMargin( 0 ); + l->addWidget( myInfo ); +} + +/*! + \brief Show mesh element information + \param long id mesh node / element ID + \param isElem show mesh element information if \c true or mesh node information if \c false +*/ +void SMESHGUI_SimpleElemInfo::showInfo( long id, bool isElem ) +{ + if ( myID == id && myIsElement == isElem ) return; + + SMESHGUI_ElemInfo::showInfo( id, isElem ); + + clear(); + + if ( myActor ) { + int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); + if ( !isElem ) { + // + // show node info + // + const SMDS_MeshElement* e = myActor->GetObject()->GetMesh()->FindNode( id ); + if ( !e ) return; + const SMDS_MeshNode* node = static_cast( e ); + + // node ID + myInfo->append( QString( "%1 #%2" ).arg( tr( "NODE" ) ).arg( id ) ); + // separator + myInfo->append( "" ); + // coordinates + myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( 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 ) ) ); + // separator + myInfo->append( "" ); + // connectivity + Connectivity connectivity = nodeConnectivity( node ); + if ( !connectivity.isEmpty() ) { + myInfo->append( QString( "%1:" ).arg( tr( "CONNECTIVITY" ) ) ); + QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) ); + con = formatConnectivity( connectivity, SMDSAbs_Edge ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "EDGES" ) ).arg( con ) ); + con = formatConnectivity( connectivity, SMDSAbs_Face ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "FACES" ) ).arg( con ) ); + con = formatConnectivity( connectivity, SMDSAbs_Volume ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "VOLUMES" ) ).arg( con ) ); + } + else { + myInfo->append( QString( "%1" ).arg( tr( "FREE_NODE" ) ).arg( id ) ); + } + } + else { + // + // show element info + // + const SMDS_MeshElement* e = myActor->GetObject()->GetMesh()->FindElement( id ); + if ( !e ) return; + + // element ID && type + QString stype; + switch( e->GetType() ) { + case SMDSAbs_0DElement: + stype = tr( "0D ELEMENT" ); break; + case SMDSAbs_Edge: + stype = tr( "EDGE" ); break; + case SMDSAbs_Face: + stype = tr( "FACE" ); break; + case SMDSAbs_Volume: + stype = tr( "VOLUME" ); break; + default: + break; + } + if ( stype.isEmpty() ) return; + myInfo->append( QString( "%1 #%2" ).arg( stype ).arg( id ) ); + // separator + myInfo->append( "" ); + // geometry type + QString gtype; + switch( e->GetEntityType() ) { + case SMDSEntity_Triangle: + case SMDSEntity_Quad_Triangle: + gtype = tr( "TRIANGLE" ); break; + case SMDSEntity_Quadrangle: + case SMDSEntity_Quad_Quadrangle: + gtype = tr( "QUADRANGLE" ); break; + case SMDSEntity_Polygon: + case SMDSEntity_Quad_Polygon: + gtype = tr( "QUADRANGLE" ); break; + case SMDSEntity_Tetra: + case SMDSEntity_Quad_Tetra: + gtype = tr( "TETRAHEDRON" ); break; + case SMDSEntity_Pyramid: + case SMDSEntity_Quad_Pyramid: + gtype = tr( "PYRAMID" ); break; + case SMDSEntity_Hexa: + case SMDSEntity_Quad_Hexa: + gtype = tr( "HEXAHEDRON" ); break; + case SMDSEntity_Penta: + case SMDSEntity_Quad_Penta: + gtype = tr( "PRISM" ); break; + case SMDSEntity_Polyhedra: + case SMDSEntity_Quad_Polyhedra: + gtype = tr( "POLYHEDRON" ); break; + default: + break; + } + if ( !gtype.isEmpty() ) + myInfo->append( QString( "%1: %2" ).arg( tr( "TYPE" ) ).arg( gtype ) ); + // quadratic flag and gravity center (any element except 0D) + if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Last ) { + // quadratic flag + myInfo->append( QString( "%1? %2" ).arg( tr( "QUADRATIC" ) ).arg( e->IsQuadratic() ? tr( "YES" ) : 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() ) ); + } + // separator + myInfo->append( "" ); + // 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 + myInfo->append( QString( "%1 %2/%3 - #%4" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ) ); + // node coordinates + myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( 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" ) ) ); + QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) ); + con = formatConnectivity( connectivity, SMDSAbs_Edge ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "EDGES" ) ).arg( con ) ); + con = formatConnectivity( connectivity, SMDSAbs_Face ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "FACES" ) ).arg( con ) ); + con = formatConnectivity( connectivity, SMDSAbs_Volume ); + if ( !con.isEmpty() ) + myInfo->append( QString( "- %1: %2" ).arg( tr( "VOLUMES" ) ).arg( con ) ); + } + else { + myInfo->append( QString( "%1" ).arg( tr( "FREE_NODE" ) ).arg( id ) ); + } + // separator + myInfo->append( "" ); + } + } + } +} + +/*! + \brief Clear mesh element information widget +*/ +void SMESHGUI_SimpleElemInfo::clear() +{ + myInfo->clear(); +} + +/*! + \class SMESHGUI_TreeElemInfo::ItemDelegate + \brief Item delegate for tree mesh info widget + \internal +*/ +class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate +{ +public: + ItemDelegate( QObject* ); + QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const; +}; + +/*! + \brief Constructor + \internal +*/ +SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ) : QItemDelegate( parent ) +{ +} + +/*! + \brief Create item editor widget + \internal +*/ +QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index ); + if ( qobject_cast( w ) ) qobject_cast( w )->setReadOnly( true ); + return w; +} + +/*! + \class SMESHGUI_TreeElemInfo + \brief Represents mesh element information in the tree-like form. +*/ + +/*! + \brief Constructor + \param parent parent widget +*/ +SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent ) +: SMESHGUI_ElemInfo( parent ) +{ + myInfo = new QTreeWidget( this ); + myInfo->setColumnCount( 2 ); + myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) ); + myInfo->header()->setStretchLastSection( true ); + myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents ); + myInfo->setItemDelegate( new ItemDelegate( myInfo ) ); + QVBoxLayout* l = new QVBoxLayout( this ); + l->setMargin( 0 ); + l->addWidget( myInfo ); +} + +/*! + \brief Show mesh element information + \param long id mesh node / element ID + \param isElem show mesh element information if \c true or mesh node information if \c false +*/ +void SMESHGUI_TreeElemInfo::showInfo( long id, bool isElem ) +{ + if ( myID == id && myIsElement == isElem ) return; + + SMESHGUI_ElemInfo::showInfo( id, isElem ); + + clear(); + + if ( myActor ) { + int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); + if ( !isElem ) { + // + // show node info + // + const SMDS_MeshElement* e = myActor->GetObject()->GetMesh()->FindNode( id ); + if ( !e ) return; + const SMDS_MeshNode* node = static_cast( e ); + + // node ID + QTreeWidgetItem* nodeItem = createItem( 0, -1 ); + nodeItem->setText( 0, tr( "NODE" ) ); + nodeItem->setText( 1, QString( "#%1" ).arg( id ) ); + nodeItem->setExpanded( true ); + // coordinates + QTreeWidgetItem* coordItem = createItem( nodeItem, 0 ); + coordItem->setText( 0, tr( "COORDINATES" ) ); + coordItem->setExpanded( true ); + QTreeWidgetItem* xItem = createItem( coordItem ); + xItem->setText( 0, "X" ); + xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + QTreeWidgetItem* yItem = createItem( coordItem ); + yItem->setText( 0, "Y" ); + yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + QTreeWidgetItem* zItem = createItem( coordItem ); + zItem->setText( 0, "Z" ); + zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + // connectivity + QTreeWidgetItem* conItem = createItem( nodeItem, 0 ); + conItem->setText( 0, tr( "CONNECTIVITY" ) ); + conItem->setExpanded( true ); + 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( 1, con ); + } + con = formatConnectivity( connectivity, SMDSAbs_Edge ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( conItem ); + i->setText( 0, tr( "EDGES" ) ); + i->setText( 1, con ); + } + con = formatConnectivity( connectivity, SMDSAbs_Face ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( conItem ); + i->setText( 0, tr( "FACES" ) ); + i->setText( 1, con ); + } + con = formatConnectivity( connectivity, SMDSAbs_Volume ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( conItem ); + i->setText( 0, tr( "VOLUMES" ) ); + i->setText( 1, con ); + } + } + else { + conItem->setText( 1, tr( "FREE_NODE" ) ); + } + } + else { + // + // show element info + // + const SMDS_MeshElement* e = myActor->GetObject()->GetMesh()->FindElement( id ); + if ( !e ) return; + + // element ID && type + QString stype; + switch( e->GetType() ) { + case SMDSAbs_0DElement: + stype = tr( "0D ELEMENT" ); break; + case SMDSAbs_Edge: + stype = tr( "EDGE" ); break; + case SMDSAbs_Face: + stype = tr( "FACE" ); break; + case SMDSAbs_Volume: + stype = tr( "VOLUME" ); break; + default: + break; + } + if ( stype.isEmpty() ) return; + QTreeWidgetItem* elemItem = createItem( 0, -1 ); + elemItem->setText( 0, stype ); + elemItem->setText( 1, QString( "#%1" ).arg( id ) ); + elemItem->setExpanded( true ); + // geometry type + QString gtype; + switch( e->GetEntityType() ) { + case SMDSEntity_Triangle: + case SMDSEntity_Quad_Triangle: + gtype = tr( "TRIANGLE" ); break; + case SMDSEntity_Quadrangle: + case SMDSEntity_Quad_Quadrangle: + gtype = tr( "QUADRANGLE" ); break; + case SMDSEntity_Polygon: + case SMDSEntity_Quad_Polygon: + gtype = tr( "QUADRANGLE" ); break; + case SMDSEntity_Tetra: + case SMDSEntity_Quad_Tetra: + gtype = tr( "TETRAHEDRON" ); break; + case SMDSEntity_Pyramid: + case SMDSEntity_Quad_Pyramid: + gtype = tr( "PYRAMID" ); break; + case SMDSEntity_Hexa: + case SMDSEntity_Quad_Hexa: + gtype = tr( "HEXAHEDRON" ); break; + case SMDSEntity_Penta: + case SMDSEntity_Quad_Penta: + gtype = tr( "PRISM" ); break; + case SMDSEntity_Polyhedra: + case SMDSEntity_Quad_Polyhedra: + gtype = tr( "POLYHEDRON" ); break; + default: + break; + } + if ( !gtype.isEmpty() ) { + QTreeWidgetItem* typeItem = createItem( elemItem, 0 ); + typeItem->setText( 0, tr( "TYPE" ) ); + typeItem->setText( 1, gtype ); + } + // quadratic flag and gravity center (any element except 0D) + if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Last ) { + // quadratic flag + QTreeWidgetItem* quadItem = createItem( elemItem, 0 ); + quadItem->setText( 0, tr( "QUADRATIC" ) ); + quadItem->setText( 1, e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) ); + // gravity center + XYZ gc = gravityCenter( e ); + QTreeWidgetItem* gcItem = createItem( elemItem, 0 ); + gcItem->setText( 0, tr( "GRAVITY_CENTER" ) ); + gcItem->setExpanded( true ); + QTreeWidgetItem* xItem = createItem( gcItem ); + xItem->setText( 0, "X" ); + xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + QTreeWidgetItem* yItem = createItem( gcItem ); + yItem->setText( 0, "Y" ); + yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + QTreeWidgetItem* zItem = createItem( gcItem ); + zItem->setText( 0, "Z" ); + zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + } + // connectivity + QTreeWidgetItem* conItem = createItem( elemItem, 0 ); + conItem->setText( 0, tr( "CONNECTIVITY" ) ); + conItem->setExpanded( true ); + 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, 0 ); + nodeItem->setText( 0, QString( "%1 %2/%3" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ) ); + nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ) ); + //nodeItem->setExpanded( true ); + // node coordinates + QTreeWidgetItem* coordItem = createItem( nodeItem ); + coordItem->setText( 0, tr( "COORDINATES" ) ); + coordItem->setExpanded( true ); + QTreeWidgetItem* xItem = createItem( coordItem ); + xItem->setText( 0, "X" ); + xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + QTreeWidgetItem* yItem = createItem( coordItem ); + yItem->setText( 0, "Y" ); + yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); + QTreeWidgetItem* zItem = createItem( coordItem ); + zItem->setText( 0, "Z" ); + 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->setExpanded( true ); + 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( 1, con ); + } + con = formatConnectivity( connectivity, SMDSAbs_Edge ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( nconItem ); + i->setText( 0, tr( "EDGES" ) ); + i->setText( 1, con ); + } + con = formatConnectivity( connectivity, SMDSAbs_Face ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( nconItem ); + i->setText( 0, tr( "FACES" ) ); + i->setText( 1, con ); + } + con = formatConnectivity( connectivity, SMDSAbs_Volume ); + if ( !con.isEmpty() ) { + QTreeWidgetItem* i = createItem( nconItem ); + i->setText( 0, tr( "VOLUMES" ) ); + i->setText( 1, con ); + } + } + } + } + } +} + +/*! + \brief Clear mesh element information widget +*/ +void SMESHGUI_TreeElemInfo::clear() +{ + myInfo->clear(); + myInfo->repaint(); +} + +/*! + \brief Create new tree item. + \param parnt parent tree widget item + \param column item column to be set bold, if it is -1, bold font will be set for all columns + \return new tree widget item +*/ +QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int column ) +{ + QTreeWidgetItem* item; + if ( parent ) + item = new QTreeWidgetItem( parent ); + else + item = new QTreeWidgetItem( myInfo ); + + item->setFlags( item->flags() | Qt::ItemIsEditable ); + + QFont f = item->font( 0 ); + f.setBold( true ); + if ( column >= 0 && column < myInfo->columnCount() ) { + item->setFont( column, f ); + } + else if ( column == -1 ) { + for ( int i = 0; i < myInfo->columnCount(); i++ ) + item->setFont( i, f ); + } + return item; +} + +/*! + \class SMESHGUI_MeshInfoDlg + \brief Mesh information dialog box +*/ + +/*! + \brief Constructor + \param parent parent widget + \param page specifies the dialog page to be shown at the start-up +*/ +SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page ) +: QDialog( parent ), myActor( 0 ) +{ + setModal( false ); + setAttribute( Qt::WA_DeleteOnClose, true ); + setWindowTitle( tr( "MESH_INFO" ) ); + setSizeGripEnabled( true ); + + myTabWidget = new QTabWidget( this ); + + // base info + + myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget ); + myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) ); + + // elem info + + QWidget* w = new QWidget( myTabWidget ); + + myMode = new QButtonGroup( this ); + myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode ); + myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode ); + myMode->button( NodeMode )->setChecked( true ); + myID = new QLineEdit( w ); + myID->setValidator( new SMESHGUI_IdValidator( this, 1 ) ); + + int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 ); + mode = qMin( 1, qMax( 0, mode ) ); + + if ( mode == 0 ) + myElemInfo = new SMESHGUI_SimpleElemInfo( w ); + else + myElemInfo = new SMESHGUI_TreeElemInfo( w ); + + QGridLayout* elemLayout = new QGridLayout( w ); + elemLayout->setMargin( MARGIN ); + elemLayout->setSpacing( SPACING ); + elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 ); + elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 ); + elemLayout->addWidget( myID, 0, 2 ); + elemLayout->addWidget( myElemInfo, 1, 0, 1, 3 ); + + myTabWidget->addTab( w, tr( "ELEM_INFO" ) ); + + QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this ); + okBtn->setAutoDefault( true ); + okBtn->setDefault( true ); + okBtn->setFocus(); + QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this ); + helpBtn->setAutoDefault( true ); + + QHBoxLayout* btnLayout = new QHBoxLayout; + btnLayout->setSpacing( SPACING ); + btnLayout->setMargin( 0 ); + + btnLayout->addWidget( okBtn ); + btnLayout->addStretch( 10 ); + btnLayout->addWidget( helpBtn ); + + QVBoxLayout* l = new QVBoxLayout ( this ); + l->setMargin( MARGIN ); + l->setSpacing( SPACING ); + l->addWidget( myTabWidget ); + l->addStretch(); + l->addLayout( btnLayout ); + + myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) ); + + connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); + 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( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) ); + connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) ); + + updateSelection(); +} + +/*! + \brief Destructor +*/ +SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg() +{ +} + +/*! + \brief Show mesh information + \param IO interactive object +*/ +void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO ) +{ + SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface( IO ); + if ( !CORBA::is_nil( obj ) ) { + myBaseInfo->showInfo( obj ); + + myActor = SMESH::FindActorByEntry( IO->getEntry() ); + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + QString ID; + int nb = 0; + if ( myActor && selector ) { + nb = myMode->checkedId() == NodeMode ? + SMESH::GetNameOfSelectedElements( selector, IO, ID ) : + SMESH::GetNameOfSelectedNodes( selector, IO, ID ); + } + if ( nb == 1 ) { + myID->setText( ID.trimmed() ); + myElemInfo->setSource( myActor ) ; + myElemInfo->showInfo( ID.toLong(), myMode->checkedId() == ElemMode ); + } + else { + myID->clear(); + myElemInfo->clear(); + } + } +} + +/*! + \brief Perform clean-up actions on the dialog box closing. +*/ +void SMESHGUI_MeshInfoDlg::reject() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + selMgr->clearFilters(); + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( ActorSelection ); + QDialog::reject(); +} + +/*! + \brief Process keyboard event + \param e key press event +*/ +void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e ) +{ + QDialog::keyPressEvent( e ); + if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) { + e->accept(); + help(); + } +} + +/*! + \brief Reactivate dialog box, when mouse pointer goes into it. +*/ +void SMESHGUI_MeshInfoDlg::enterEvent( QEvent* ) +{ + activate(); +} + +/*! + \brief Setup selection mode depending on the current dialog box state. +*/ +void SMESHGUI_MeshInfoDlg::updateSelection() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + + disconnect( selMgr, 0, this, 0 ); + selMgr->clearFilters(); + + if ( myTabWidget->currentIndex() == BaseInfo ) { + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( ActorSelection ); + } + else { + if ( myMode->checkedId() == NodeMode ) { + SMESH::SetPointRepresentation( true ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( NodeSelection ); + } + else { + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( CellSelection ); + } + } + + int oldID = myID->text().toLong(); + SMESH_Actor* oldActor = myActor; + myID->clear(); + + connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) ); + updateInfo(); + + if ( oldActor == myActor && myActor && oldID ) { + myID->setText( QString::number( oldID ) ); + idChanged(); + } +} + +/*! + \brief Show help page +*/ +void SMESHGUI_MeshInfoDlg::help() +{ + SMESH::ShowHelpFile( myTabWidget->currentIndex() == BaseInfo ? + "mesh_infos_page.html#advanced_mesh_infos_anchor" : + "mesh_infos_page.html#mesh_element_info_anchor" ); +} + +/*! + \brief Show mesh information +*/ +void SMESHGUI_MeshInfoDlg::updateInfo() +{ + SUIT_OverrideCursor wc; + + SALOME_ListIO selected; + SMESHGUI::selectionMgr()->selectedObjects( selected ); + + if ( selected.Extent() == 1 ) { + Handle(SALOME_InteractiveObject) IO = selected.First(); + showInfo( IO ); + } +// else { +// myBaseInfo->clear(); +// myElemInfo->clear(); +// } +} + +/*! + \brief Activate dialog box +*/ +void SMESHGUI_MeshInfoDlg::activate() +{ + SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog(); + SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this ); + myTabWidget->setEnabled( true ); + updateSelection(); +} + +/*! + \brief Deactivate dialog box +*/ +void SMESHGUI_MeshInfoDlg::deactivate() +{ + myTabWidget->setEnabled( false ); + disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) ); +} + +/*! + \brief Called when users switches between node / element modes. +*/ +void SMESHGUI_MeshInfoDlg::modeChanged() +{ + myID->clear(); + updateSelection(); +} + +/*! + \brief Caled when users prints mesh element ID in the corresponding field. +*/ +void SMESHGUI_MeshInfoDlg::idChanged() +{ + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + if ( myActor && selector ) { + Handle(SALOME_InteractiveObject) IO = myActor->getIO(); + TColStd_MapOfInteger ID; + ID.Add( myID->text().toLong() ); + selector->AddOrRemoveIndex( IO, ID, false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->highlight( IO, true, true ); + myElemInfo->showInfo( myID->text().toLong(), myMode->checkedId() == ElemMode ); + } +} diff --git a/src/SMESHGUI/SMESHGUI_MeshInfo.h b/src/SMESHGUI/SMESHGUI_MeshInfo.h new file mode 100644 index 000000000..ae22e5ac0 --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_MeshInfo.h @@ -0,0 +1,220 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SMESHGUI_MeshInfo.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) + +#ifndef SMESHGUI_MESHINFO_H +#define SMESHGUI_MESHINFO_H + +#include "SMESH_SMESHGUI.hxx" +#include + +#include +#include +#include +#include +#include + +#include +#include CORBA_SERVER_HEADER(SMESH_Mesh) + +class QButtonGroup; +class QLabel; +class QLineEdit; +class QTabWidget; +class QTextBrowser; +class QTreeWidget; +class QTreeWidgetItem; +class SMESH_Actor; +class SMDS_MeshNode; +class SMDS_MeshElement; + +class SMESHGUI_EXPORT SMESHGUI_MeshInfo : public QFrame +{ + Q_OBJECT; + + enum { + iName, + iObject, + iNodesStart, + iNodes, + iNodesEnd, + iElementsStart = iNodesEnd, + iElements, + i0DStart, + i0D, + i0DEnd, + i1DStart = i0DEnd, + i1D, + i1DEnd, + i2DStart = i1DEnd, + i2D, + i2DTriangles, + i2DQuadrangles, + i2DPolygons, + i2DEnd, + i3DStart = i2DEnd, + i3D, + i3DTetrahedrons, + i3DHexahedrons, + i3DPyramids, + i3DPrisms, + i3DPolyhedrons, + i3DEnd, + iElementsEnd = i3DEnd + }; + + enum { + iSingle = 1, + iTotal = iSingle, + iLinear, + iQuadratic + }; + + typedef QList wlist; + typedef QVector iwlist; + +public: + SMESHGUI_MeshInfo( QWidget* = 0 ); + ~SMESHGUI_MeshInfo(); + + void showInfo( SMESH::SMESH_IDSource_ptr ); + void clear(); + +private: + enum { Bold = 0x01, Italic = 0x02 }; + + QLabel* createField(); + QWidget* createLine(); + void setFontAttributes( QWidget*, int, bool = true ); + void setFieldsVisible( int, int, bool ); + +private: + iwlist myWidgets; +}; + +class SMESHGUI_EXPORT SMESHGUI_ElemInfo : public QWidget +{ + Q_OBJECT; + +public: + SMESHGUI_ElemInfo( QWidget* = 0 ); + ~SMESHGUI_ElemInfo(); + + void setSource( SMESH_Actor* ); + virtual void showInfo( long, bool ); + virtual void clear() = 0; + +protected: + struct XYZ + { + double myX, myY, myZ; + XYZ() { myX = myY = myZ = 0.0; } + void add( double x, double y, double z ) { myX += x; myY += y; myZ += z; } + void divide( double a ) { if ( a != 0.) { myX /= a; myY /= a; myZ /= a; } } + double x() const { return myX; } + double y() const { return myY; } + double z() const { return myZ; } + }; + typedef QMap< int, QList > Connectivity; + + Connectivity nodeConnectivity( const SMDS_MeshNode* ); + QString formatConnectivity( Connectivity, int ); + XYZ gravityCenter( const SMDS_MeshElement* ); + +protected: + SMESH_Actor* myActor; + long myID; + int myIsElement; +}; + +class SMESHGUI_EXPORT SMESHGUI_SimpleElemInfo : public SMESHGUI_ElemInfo +{ +public: + SMESHGUI_SimpleElemInfo( QWidget* = 0 ); + + void showInfo( long, bool ); + void clear(); + +private: + QTextBrowser* myInfo; +}; + +class SMESHGUI_EXPORT SMESHGUI_TreeElemInfo : public SMESHGUI_ElemInfo +{ + class ItemDelegate; + +public: + SMESHGUI_TreeElemInfo( QWidget* = 0 ); + + void showInfo( long, bool ); + void clear(); + +private: + QTreeWidgetItem* createItem( QTreeWidgetItem* = 0, int = 100 ); + +private: + QTreeWidget* myInfo; +}; + +class SMESHGUI_EXPORT SMESHGUI_MeshInfoDlg : public QDialog +{ + Q_OBJECT; + + enum { NodeMode, ElemMode }; + +public: + //! Information type + enum { + BaseInfo, //!< base mesh information + ElemInfo //!< mesh element information + }; + + SMESHGUI_MeshInfoDlg( QWidget* = 0, int = BaseInfo ); + ~SMESHGUI_MeshInfoDlg(); + + void showInfo( const Handle(SALOME_InteractiveObject)& ); + void reject(); + +protected: + void keyPressEvent( QKeyEvent* ); + void enterEvent( QEvent* ); + +private slots: + void help(); + void updateSelection(); + void updateInfo(); + void activate(); + void deactivate(); + void modeChanged(); + void idChanged(); + +private: + QTabWidget* myTabWidget; + SMESHGUI_MeshInfo* myBaseInfo; + QButtonGroup* myMode; + QLineEdit* myID; + SMESHGUI_ElemInfo* myElemInfo; + SMESH_Actor* myActor; +}; + +#endif // SMESHGUI_MESHINFO_H diff --git a/src/SMESHGUI/SMESHGUI_MeshInfosDlg.cxx b/src/SMESHGUI/SMESHGUI_MeshInfosDlg.cxx index 01ba22253..40def53ab 100644 --- a/src/SMESHGUI/SMESHGUI_MeshInfosDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshInfosDlg.cxx @@ -141,7 +141,9 @@ SMESHGUI_MeshInfosDlg::SMESHGUI_MeshInfosDlg(SMESHGUI* theModule): // buttons --> OK and Help buttons myOkBtn = new QPushButton(tr("SMESH_BUT_OK" ), myButtonsGroup); - myOkBtn->setAutoDefault(true); myOkBtn->setDefault(true); + myOkBtn->setAutoDefault(true); + myOkBtn->setDefault(true); + myOkBtn->setFocus(); myHelpBtn = new QPushButton(tr("SMESH_BUT_HELP" ), myButtonsGroup); myHelpBtn->setAutoDefault(true); diff --git a/src/SMESHGUI/SMESHGUI_MeshOp.cxx b/src/SMESHGUI/SMESHGUI_MeshOp.cxx index 4ceb159ee..48b4fae6e 100644 --- a/src/SMESHGUI/SMESHGUI_MeshOp.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshOp.cxx @@ -19,12 +19,11 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_MeshOp.cxx +// Author : Sergey LITONIN, Open CASCADE S.A.S. -// SMESH SMESHGUI : GUI for SMESH component -// File : SMESHGUI_MeshOp.cxx -// Author : Sergey LITONIN, Open CASCADE S.A.S. // SMESH includes -// #include "SMESHGUI_MeshOp.h" #include "SMESHGUI.h" @@ -72,6 +71,10 @@ #include #include CORBA_CLIENT_HEADER(SMESH_Gen) +//To disable automatic genericobj management, the following line should be commented. +//Otherwise, it should be uncommented. Refer to KERNEL_SRC/src/SALOMEDSImpl/SALOMEDSImpl_AttributeIOR.cxx +#define WITHGENERICOBJ + //================================================================================ /*! * \brief Constructor @@ -280,7 +283,6 @@ SUIT_SelectionFilter* SMESHGUI_MeshOp::createFilter( const int theId ) const * \retval bool - check result */ //================================================================================ - bool SMESHGUI_MeshOp::isSubshapeOk() const { if ( !myToCreate || myIsMesh ) // not submesh creation @@ -343,11 +345,10 @@ bool SMESHGUI_MeshOp::isSubshapeOk() const //================================================================================ /*! * \brief Return name of the algorithm that does not support submeshes and makes - * submesh creation useless + * submesh creation useless * \retval char* - string is to be deleted!!! */ //================================================================================ - char* SMESHGUI_MeshOp::isSubmeshIgnored() const { if ( myToCreate && !myIsMesh ) { @@ -393,7 +394,6 @@ char* SMESHGUI_MeshOp::isSubmeshIgnored() const * \retval _PTR(SObject) - the found submesh SObject */ //================================================================================ - _PTR(SObject) SMESHGUI_MeshOp::getSubmeshByGeom() const { QString aMeshEntry = myDlg->selectedObject( SMESHGUI_MeshDlg::Mesh ); @@ -581,7 +581,7 @@ void SMESHGUI_MeshOp::selectionDone() bool editSubmesh = ( !sm->_is_nil() && SUIT_MessageBox::question( myDlg, tr( "SMESH_WARNING" ), tr( "EDIT_SUBMESH_QUESTION"), - SUIT_MessageBox::Yes | + SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No ) == SUIT_MessageBox::Yes ); @@ -743,7 +743,6 @@ bool SMESHGUI_MeshOp::isValid( QString& theMess ) const * \retval bool - check result */ //================================================================================ - static bool isCompatible(const HypothesisData* theAlgoData, const HypothesisData* theHypData, const int theHypType) @@ -861,6 +860,7 @@ void SMESHGUI_MeshOp::existingHyps( const int theDim, if ( !aHypVar->_is_nil() ) { HypothesisData* aData = SMESH::GetHypothesisData( aHypVar->GetName() ); + if ( !aData) continue; if ( ( theDim == -1 || aData->Dim.contains( theDim ) ) && ( isCompatible ( theAlgoData, aData, theHypType )) && ( isAux == aData->IsAux )) @@ -886,7 +886,6 @@ void SMESHGUI_MeshOp::existingHyps( const int theDim, * \retval SMESH::SMESH_Hypothesis_var - the hypothesis holding parameter values */ //================================================================================ - SMESH::SMESH_Hypothesis_var SMESHGUI_MeshOp::getInitParamsHypothesis( const QString& aHypType, const QString& aServerLib ) const @@ -972,7 +971,6 @@ SMESHGUI_MeshOp::getInitParamsHypothesis( const QString& aHypType, * \retval int - dimention */ //================================================================================ - static int getTabDim (const QObject* tab, SMESHGUI_MeshDlg* dlg ) { int aDim = -1; @@ -1030,7 +1028,6 @@ namespace * \param theTypeName - specifies hypothesis to be created */ //================================================================================ - void SMESHGUI_MeshOp::createHypothesis(const int theDim, const int theType, const QString& theTypeName) @@ -1064,7 +1061,12 @@ void SMESHGUI_MeshOp::createHypothesis(const int theDim, QString aClientLibName = aData->ClientLibName; if (aClientLibName == "") { // Call hypothesis creation server method (without GUI) - SMESH::CreateHypothesis(theTypeName, aHypName, false); + SMESH::SMESH_Hypothesis_var aHyp = + SMESH::CreateHypothesis(theTypeName, aHypName, false); +#ifdef WITHGENERICOBJ + if (!CORBA::is_nil(aHyp)) + aHyp->Destroy(); +#endif } else { // Get hypotheses creator client (GUI) // BUG 0020378 @@ -1086,13 +1088,13 @@ void SMESHGUI_MeshOp::createHypothesis(const int theDim, aGeomEntry = myDlg->selectedObject( SMESHGUI_MeshDlg::Geom ); aMeshEntry = myDlg->selectedObject( SMESHGUI_MeshDlg::Mesh ); anObjEntry = myDlg->selectedObject( SMESHGUI_MeshDlg::Obj ); - + if ( aMeshEntry != "" ) { // Get Geom object from Mesh _PTR(SObject) pObj = studyDS()->FindObjectID( aMeshEntry.toLatin1().data() ); GEOM::GEOM_Object_var aGeomVar = SMESH::GetShapeOnMeshOrSubMesh( pObj ); aMeshEntry = ( aGeomVar->_is_nil() ) ? "" : aMeshEntry = aGeomVar->GetStudyEntry(); } - + if ( aMeshEntry == "" && aGeomEntry == "" ) { _PTR(SObject) pObj = studyDS()->FindObjectID( anObjEntry.toLatin1().data() ); GEOM::GEOM_Object_var aGeomVar = SMESH::GetShapeOnMeshOrSubMesh( pObj ); @@ -1117,7 +1119,7 @@ void SMESHGUI_MeshOp::createHypothesis(const int theDim, } } } - + aCreator->setShapeEntry( aGeomEntry ); if ( aMeshEntry != "" ) aCreator->setMainShapeEntry( aMeshEntry ); @@ -1125,8 +1127,14 @@ void SMESHGUI_MeshOp::createHypothesis(const int theDim, aCreator->create(initParamHyp, aHypName, myDlg, this, SLOT( onHypoCreated( int ) ) ); dialog = true; } - else - SMESH::CreateHypothesis(theTypeName, aHypName, false); + else { + SMESH::SMESH_Hypothesis_var aHyp = + SMESH::CreateHypothesis(theTypeName, aHypName, false); +#ifdef WITHGENERICOBJ + if (!CORBA::is_nil(aHyp)) + aHyp->Destroy(); +#endif + } } if( !dialog ) @@ -1274,7 +1282,6 @@ void SMESHGUI_MeshOp::onHypoEdited( int result ) * \retval HypothesisData* - result data, may be 0 */ //================================================================================ - HypothesisData* SMESHGUI_MeshOp::hypData( const int theDim, const int theHypType, const int theIndex) @@ -1292,7 +1299,6 @@ HypothesisData* SMESHGUI_MeshOp::hypData( const int theDim, * \param theIndex - algorithm index */ //================================================================================ - void SMESHGUI_MeshOp::onAlgoSelected( const int theIndex, const int theDim ) { @@ -1588,7 +1594,13 @@ bool SMESHGUI_MeshOp::createMesh( QString& theMess ) if ( !anAlgoVar->_is_nil() ) SMESH::AddHypothesisOnMesh( aMeshVar, anAlgoVar ); } - +#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 (aMeshSO) + aMeshVar->Destroy(); +#endif } return true; } @@ -1676,7 +1688,7 @@ bool SMESHGUI_MeshOp::createSubMesh( QString& theMess ) QString aNewGeomGroupName ("Auto_group_for_"); aNewGeomGroupName += aName; SALOMEDS::SObject_var aNewGroupSO = - geomGen->AddInStudy(aSMESHGen->GetCurrentStudy(), aGeomVar, + geomGen->AddInStudy(aSMESHGen->GetCurrentStudy(), aGeomVar, aNewGeomGroupName.toLatin1().data(), mainGeom); } } @@ -1846,7 +1858,12 @@ SMESH::SMESH_Hypothesis_var SMESHGUI_MeshOp::getAlgo( const int theDim ) if (aClientLibName == "") { // Call hypothesis creation server method (without GUI) - SMESH::CreateHypothesis(aHypName, aHypData->Label, true); + SMESH::SMESH_Hypothesis_var aHyp = + SMESH::CreateHypothesis(aHypName, aHypName, true); +#ifdef WITHGENERICOBJ + if (!CORBA::is_nil(aHyp)) + aHyp->Destroy(); +#endif } else { @@ -1858,8 +1875,14 @@ SMESH::SMESH_Hypothesis_var SMESHGUI_MeshOp::getAlgo( const int theDim ) // Create algorithm if (aCreator) aCreator->create(true, aHypName, myDlg, 0, QString::null ); - else - SMESH::CreateHypothesis(aHypName, aHypData->Label, true); + else { + SMESH::SMESH_Hypothesis_var aHyp = + SMESH::CreateHypothesis(aHypName, aHypName, true); +#ifdef WITHGENERICOBJ + if (!CORBA::is_nil(aHyp)) + aHyp->Destroy(); +#endif + } } QStringList tmpList; _PTR(SComponent) aFather = SMESH::GetActiveStudyDocument()->FindComponent( "SMESH" ); @@ -2160,14 +2183,14 @@ bool SMESHGUI_MeshOp::editMeshOrSubMesh( QString& theMess ) //================================================================================ /*! * \brief Verifies whether given operator is valid for this one - * \param theOtherOp - other operation - * \return Returns TRUE if the given operator is valid for this one, FALSE otherwise -* -* method redefined from base class verifies whether given operator is valid for -* this one (i.e. can be started "above" this operator). In current implementation method -* retuns false if theOtherOp operation is not intended for deleting objects or mesh -* elements. -*/ + * \param theOtherOp - other operation + * \return Returns TRUE if the given operator is valid for this one, FALSE otherwise + * + * method redefined from base class verifies whether given operator is valid for + * this one (i.e. can be started "above" this operator). In current implementation method + * retuns false if theOtherOp operation is not intended for deleting objects or mesh + * elements. + */ //================================================================================ bool SMESHGUI_MeshOp::isValid( SUIT_Operation* theOp ) const { @@ -2177,10 +2200,9 @@ bool SMESHGUI_MeshOp::isValid( SUIT_Operation* theOp ) const //================================================================================ /*! * \brief SLOT. Is called when the user selects a way of geometry selection - * \param theByMesh - true if the user wants to find geometry by mesh element + * \param theByMesh - true if the user wants to find geometry by mesh element */ //================================================================================ - void SMESHGUI_MeshOp::onGeomSelectionByMesh( bool theByMesh ) { if ( theByMesh ) { @@ -2212,7 +2234,6 @@ void SMESHGUI_MeshOp::onGeomSelectionByMesh( bool theByMesh ) * \brief SLOT. Is called when Ok is pressed in SMESHGUI_ShapeByMeshDlg */ //================================================================================ - void SMESHGUI_MeshOp::onPublishShapeByMeshDlg(SUIT_Operation* op) { if ( myShapeByMeshOp == op ) { @@ -2236,7 +2257,6 @@ void SMESHGUI_MeshOp::onPublishShapeByMeshDlg(SUIT_Operation* op) * \brief SLOT. Is called when Close is pressed in SMESHGUI_ShapeByMeshDlg */ //================================================================================ - void SMESHGUI_MeshOp::onCloseShapeByMeshDlg(SUIT_Operation* op) { if ( myShapeByMeshOp == op && myDlg ) { @@ -2247,10 +2267,9 @@ void SMESHGUI_MeshOp::onCloseShapeByMeshDlg(SUIT_Operation* op) //================================================================================ /*! * \brief Selects a SObject - * \param theSObj - the SObject to select + * \param theSObj - the SObject to select */ //================================================================================ - void SMESHGUI_MeshOp::selectObject( _PTR(SObject) theSObj ) const { if ( LightApp_SelectionMgr* sm = selectionMgr() ) { diff --git a/src/SMESHGUI/SMESHGUI_MeshUtils.cxx b/src/SMESHGUI/SMESHGUI_MeshUtils.cxx index 0763be3ed..7d48093e2 100644 --- a/src/SMESHGUI/SMESHGUI_MeshUtils.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshUtils.cxx @@ -27,6 +27,7 @@ // #include "SMESHGUI_MeshUtils.h" +#include "SMESHGUI.h" #include "SMESHGUI_Utils.h" // SALOME KERNEL includes @@ -38,6 +39,7 @@ // IDL includes #include #include CORBA_SERVER_HEADER(SMESH_Group) +#include CORBA_SERVER_HEADER(SMESH_Measurements) namespace SMESH { @@ -82,4 +84,53 @@ namespace SMESH } return baseName; } + + QString UniqueName(const QString& theBaseName, _PTR(SObject) theParent, const QString& thePostfix) + { + QString baseName = thePostfix.isEmpty() ? + theBaseName : theBaseName + "_" + thePostfix; + QString name = baseName; + if ( _PTR(Study) aStudy = GetActiveStudyDocument() ) { + _PTR(SObject) p = theParent; + if ( !p ) p = aStudy->FindComponent( "SMESH" ); + if ( p ) { + _PTR(ChildIterator) iter = aStudy->NewChildIterator( p ); + int idx = 0; + while( true ) { + bool found = false; + for ( ; iter->More(); iter->Next() ) { + _PTR(SObject) so = iter->Value(); + if ( !so ) continue; // skip bad objects + _PTR(SObject) ref; + if ( so->ReferencedObject( ref ) ) continue; // skip references + QString n = so->GetName().c_str(); + if ( !n.isEmpty() && n == name ) { + QStringList names = name.split("_", QString::KeepEmptyParts); + if ( names.count() > 0 ) { + bool ok; + names.last().toInt( &ok ); + if ( ok ) + names.removeLast(); + } + names.append( QString::number( ++idx ) ); + name = names.join( "_" ); + found = true; + break; + } + } + if ( !found ) break; + } + } + } + return name; + } + + SMESH::Measurements_var& GetMeasurements() + { + static SMESH::Measurements_var aMeasurements; + if (CORBA::is_nil(aMeasurements)) { + aMeasurements = SMESHGUI::GetSMESHGen()->CreateMeasurements(); + } + return aMeasurements; + } } // end of namespace SMESH diff --git a/src/SMESHGUI/SMESHGUI_MeshUtils.h b/src/SMESHGUI/SMESHGUI_MeshUtils.h index 5edffe9f3..a5371f56b 100644 --- a/src/SMESHGUI/SMESHGUI_MeshUtils.h +++ b/src/SMESHGUI/SMESHGUI_MeshUtils.h @@ -36,9 +36,15 @@ // SALOME GUI includes #include +// SALOME KERNEL includes +#include + // IDL includes #include #include CORBA_SERVER_HEADER(SMESH_Mesh) +#include CORBA_SERVER_HEADER(SMESH_Measurements) + +class SALOMEDSClient_SObject; namespace SMESH { @@ -47,6 +53,10 @@ namespace SMESH SMESHGUI_EXPORT QString UniqueMeshName( const QString&, const QString& = QString() ); + SMESHGUI_EXPORT + QString UniqueName( const QString&, _PTR(SObject) = _PTR(SObject)(), const QString& = QString() ); + + SMESHGUI_EXPORT SMESH::Measurements_var& GetMeasurements(); } #endif // SMESHGUI_MESHUTILS_H diff --git a/src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx b/src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx index 341ffb284..ad420496e 100755 --- a/src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx @@ -1489,9 +1489,9 @@ SMESHGUI_CuttingIntoTetraDlg::SMESHGUI_CuttingIntoTetraDlg(SMESHGUI* theModule) if ( hasHexa ) { - myGroupChoice->button(2)->hide(); myGroupChoice->button(0)->setText( tr("SPLIT_HEX_TO_5_TETRA")); myGroupChoice->button(1)->setText( tr("SPLIT_HEX_TO_6_TETRA")); + myGroupChoice->button(2)->setText( tr("SPLIT_HEX_TO_24_TETRA")); myCriterionGrp->setTitle( tr("SPLIT_METHOD")); myCriterionGrp->show(); @@ -1512,7 +1512,7 @@ bool SMESHGUI_CuttingIntoTetraDlg::process (SMESH::SMESH_MeshEditor_ptr theEdito { SMESH::SMESH_IDSource_var obj = theObj; if ( CORBA::is_nil( obj )) - obj = theEditor->MakeIDSource( theIds ); + obj = theEditor->MakeIDSource( theIds, myEntityType ? SMESH::VOLUME : SMESH::FACE ); try { theEditor->SplitVolumesIntoTetra( obj, myGroupChoice->checkedId()+1 ); } diff --git a/src/SMESHGUI/SMESHGUI_NodesDlg.cxx b/src/SMESHGUI/SMESHGUI_NodesDlg.cxx index 84abe5242..2707c85d1 100644 --- a/src/SMESHGUI/SMESHGUI_NodesDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_NodesDlg.cxx @@ -452,15 +452,15 @@ bool SMESHGUI_NodesDlg::ClickOnApply() for ( int i = 1; i < ComboBox_GroupName->count(); i++ ) { QString aName = ComboBox_GroupName->itemText( i ); if ( aGroupName == aName && ( i == ComboBox_GroupName->currentIndex() || idx == 0 ) ) - idx = i; + idx = i; } if ( idx > 0 ) { SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( myGroups[idx-1] ); if ( !aGeomGroup->_is_nil() ) { - int res = SUIT_MessageBox::question( this, tr( "SMESH_WRN_WARNING" ), - tr( "MESH_STANDALONE_GRP_CHOSEN" ).arg( aGroupName ), - tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ); - if ( res == 1 ) return false; + int res = SUIT_MessageBox::question( this, tr( "SMESH_WRN_WARNING" ), + tr( "MESH_STANDALONE_GRP_CHOSEN" ).arg( aGroupName ), + tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ); + if ( res == 1 ) return false; } aGroup = myGroups[idx-1]; } @@ -478,21 +478,21 @@ bool SMESHGUI_NodesDlg::ClickOnApply() // create new group aGroupUsed = SMESH::AddGroup( myMesh, SMESH::NODE, aGroupName ); if ( !aGroupUsed->_is_nil() ) { - myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroupUsed)); - ComboBox_GroupName->addItem( aGroupName ); + myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroupUsed)); + ComboBox_GroupName->addItem( aGroupName ); } } else { SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGroup ); if ( !aGeomGroup->_is_nil() ) { - aGroupUsed = myMesh->ConvertToStandalone( aGeomGroup ); - if ( !aGroupUsed->_is_nil() && idx > 0 ) { - myGroups[idx-1] = SMESH::SMESH_GroupBase::_duplicate(aGroupUsed); - SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); - } + aGroupUsed = myMesh->ConvertToStandalone( aGeomGroup ); + if ( !aGroupUsed->_is_nil() && idx > 0 ) { + myGroups[idx-1] = SMESH::SMESH_GroupBase::_duplicate(aGroupUsed); + SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); + } } else - aGroupUsed = SMESH::SMESH_Group::_narrow( aGroup ); + aGroupUsed = SMESH::SMESH_Group::_narrow( aGroup ); } if ( !aGroupUsed->_is_nil() ) { @@ -529,6 +529,8 @@ bool SMESHGUI_NodesDlg::ClickOnApply() } SMESHGUI::Modified(); + SMESH::UpdateView(); + mySimulation->SetVisibility(false); return true; } @@ -623,10 +625,10 @@ void SMESHGUI_NodesDlg::SelectionIntoArgument() for( int i = 0, n = aListOfGroups.length(); i < n; i++ ) { SMESH::SMESH_GroupBase_var aGroup = aListOfGroups[i]; if ( !aGroup->_is_nil() && aGroup->GetType() == SMESH::NODE ) { - QString aGroupName( aGroup->GetName() ); - if ( !aGroupName.isEmpty() ) { - myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroup)); - ComboBox_GroupName->addItem( aGroupName ); + QString aGroupName( aGroup->GetName() ); + if ( !aGroupName.isEmpty() ) { + myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroup)); + ComboBox_GroupName->addItem( aGroupName ); } } } diff --git a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx index ec3a4d14f..43640501e 100644 --- a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx @@ -33,6 +33,8 @@ #include "SMESHGUI_Utils.h" #include +#include +#include // SALOME GUI includes #include @@ -63,7 +65,6 @@ // VTK includes #include -#include #include #define MINIMUM_WIDTH 70 @@ -279,8 +280,35 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* myOriginDimGrpLayout->addWidget( myHeightSpin, 1, 3 ); aTopLayout->addWidget( myOriginDimGrp ); + /******************************************************************************/ - /***************************************************************/ + // Destribution + myDistributionGrp = new QGroupBox ( tr( "SMESH_DISTRIBUTION_SCALARBAR" ), this ); + myDistributionGrp->setCheckable(true); + QHBoxLayout* aDistributionGrpLayout = new QHBoxLayout( myDistributionGrp ); + aDistributionGrpLayout->setSpacing( SPACING_SIZE ); aDistributionGrpLayout->setMargin( MARGIN_SIZE ); + + myDistribColorGrp = new QButtonGroup( this ); + + myDMonoColor = new QRadioButton( tr( "SMESH_MONOCOLOR" ) , myDistributionGrp ); + myDMultiColor = new QRadioButton( tr( "SMESH_MULTICOLOR" ), myDistributionGrp ); + myDMonoColor->setChecked( true ); + + 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 ); QHBoxLayout* myButtonGrpLayout = new QHBoxLayout( myButtonGrp ); @@ -376,6 +404,25 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* setOriginAndSize(myIniX, myIniY, myIniW, myIniH); + + bool distributionVisibility = mgr->booleanValue("SMESH","distribution_visibility"); + myDistributionGrp->setChecked(distributionVisibility); + + int coloringType = mgr->integerValue("SMESH", "distribution_coloring_type", 0); + if( coloringType == SMESH_MONOCOLOR_TYPE ) { + myDMultiColor->setChecked(true); + onDistributionChanged(myDistribColorGrp->id(myDMultiColor)); + } else { + myDMonoColor->setChecked(true); + onDistributionChanged(myDistribColorGrp->id(myDMonoColor)); + } + + QColor distributionColor = mgr->colorValue("SMESH", "distribution_color", + QColor(255, 255, 255)); + myMonoColorBtn->setColor(distributionColor); + + + // --> then init from selection if necessary onSelectionChanged(); @@ -388,10 +435,11 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* connect( myXSpin, SIGNAL( valueChanged( double ) ), this, SLOT( onXYChanged() ) ); connect( myYSpin, SIGNAL( valueChanged( double ) ), this, SLOT( onXYChanged() ) ); connect( aOrientationGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( onOrientationChanged() ) ); + connect( myDistribColorGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( onDistributionChanged( int ) ) ); connect( mySelectionMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( onSelectionChanged() ) ); connect( mySMESHGUI, SIGNAL( SignalCloseAllDialogs() ), this, SLOT( onCancel() ) ); - myHelpFileName = "about_quality_controls_page.html"; + myHelpFileName = "quality_page.html"; } //================================================================================================= @@ -430,7 +478,7 @@ bool SMESHGUI_Preferences_ScalarBarDlg::onApply() // Scalar Bar properties if (!myActor) return false; - vtkScalarBarActor* myScalarBarActor = myActor->GetScalarBarActor(); + SMESH_ScalarBarActor* myScalarBarActor = myActor->GetScalarBarActor(); vtkTextProperty* aTitleTextPrp = myScalarBarActor->GetTitleTextProperty(); QColor aTColor = myTitleColorBtn->color(); @@ -461,7 +509,18 @@ bool SMESHGUI_Preferences_ScalarBarDlg::onApply() myScalarBarActor->SetLabelTextProperty( aLabelsTextPrp ); myScalarBarActor->SetNumberOfLabels( myLabelsSpin->value() ); - myScalarBarActor->SetMaximumNumberOfColors( myColorsSpin->value() ); + if( myColorsSpin->value() != myScalarBarActor->GetMaximumNumberOfColors() ) { + myScalarBarActor->SetMaximumNumberOfColors( myColorsSpin->value() ); + SMESH::Controls::FunctorPtr fn = myActor->GetFunctor(); + SMESH::Controls::NumericalFunctor* aNumericalFunctor = dynamic_cast(fn.get()); + if( aNumericalFunctor ) { + int nbIntervals = myColorsSpin->value(); + std::vector nbEvents; + std::vector funValues; + aNumericalFunctor->GetHistogram(nbIntervals, nbEvents, funValues); + myScalarBarActor->SetDistribution(nbEvents); + } + } if ( myHorizRadioBtn->isChecked() ) myScalarBarActor->SetOrientationToHorizontal(); @@ -472,6 +531,21 @@ bool SMESHGUI_Preferences_ScalarBarDlg::onApply() myScalarBarActor->SetWidth( myWidthSpin->value() ); myScalarBarActor->SetHeight( myHeightSpin->value() ); + // Distribution + myScalarBarActor->SetDistributionVisibility((int)myDistributionGrp->isChecked()); + if( myDistributionGrp->isChecked() ) { + int ColoringType = myDMultiColor->isChecked() ? SMESH_MULTICOLOR_TYPE : SMESH_MONOCOLOR_TYPE; + myScalarBarActor->SetDistributionColoringType(ColoringType); + if( !myDMultiColor->isChecked() ) { + QColor aTColor = myMonoColorBtn->color(); + double rgb[3]; + rgb [0] = aTColor.red()/255.; + rgb [1] = aTColor.green()/255.; + rgb [2] = aTColor.blue()/255.; + myScalarBarActor->SetDistributionColor(rgb); + } + } + double aMin = myMinEdit->text().toDouble(); double aMax = myMaxEdit->text().toDouble(); vtkLookupTable* myLookupTable = @@ -540,7 +614,7 @@ void SMESHGUI_Preferences_ScalarBarDlg::onSelectionChanged() SMESH_Actor* anActor = SMESH::FindActorByEntry(anIO->getEntry()); if ( anActor && anActor->GetScalarBarActor() && anActor->GetControlMode() != SMESH_Actor::eNone ) { myActor = anActor; - vtkScalarBarActor* myScalarBarActor = myActor->GetScalarBarActor(); + SMESH_ScalarBarActor* myScalarBarActor = myActor->GetScalarBarActor(); if ( myScalarBarActor->GetLookupTable() ) { vtkFloatingPointType *range = myScalarBarActor->GetLookupTable()->GetRange(); @@ -581,6 +655,17 @@ void SMESHGUI_Preferences_ScalarBarDlg::onSelectionChanged() myIniH = myScalarBarActor->GetHeight(); setOriginAndSize( myIniX, myIniY, myIniW, myIniH ); + myDistributionGrp->setChecked((bool)myScalarBarActor->GetDistributionVisibility()); + int coloringType = myScalarBarActor->GetDistributionColoringType(); + myScalarBarActor->GetDistributionColor( aTColor ); + myMonoColorBtn->setColor( QColor( (int)( aTColor[0]*255 ), (int)( aTColor[1]*255 ), (int)( aTColor[2]*255 ) ) ); + if ( coloringType == SMESH_MONOCOLOR_TYPE ) { + myDMonoColor->setChecked(true); + onDistributionChanged(myDistribColorGrp->id(myDMonoColor)); + } else { + myDMultiColor->setChecked(true); + onDistributionChanged(myDistribColorGrp->id(myDMultiColor)); + } myRangeGrp->setEnabled( true ); myFontGrp->setEnabled( true ); myLabColorGrp->setEnabled( true ); @@ -651,6 +736,19 @@ void SMESHGUI_Preferences_ScalarBarDlg::setOriginAndSize( const double x, onXYChanged(); } + +//================================================================================================= +/*! + * SMESHGUI_Preferences_ScalarBarDlg::onDistributionChanged + * + * Called when coloring type of the distribution is changed + */ +//================================================================================================= +void SMESHGUI_Preferences_ScalarBarDlg::onDistributionChanged( int id ) { + myMonoColorBtn->setEnabled(myDistribColorGrp->id(myDMonoColor) == id); + myDistributionColorLbl->setEnabled(myDistribColorGrp->id(myDMonoColor) == id); +} + //================================================================================================= /*! * SMESHGUI_Preferences_ScalarBarDlg::onOrientationChanged diff --git a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.h b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.h index c71c43cda..42058ee2b 100644 --- a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.h +++ b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.h @@ -40,6 +40,8 @@ class QLineEdit; class QPushButton; class QToolButton; class QRadioButton; +class QButtonGroup; +class QLabel; class SMESHGUI; class SMESH_Actor; @@ -77,6 +79,7 @@ protected slots: void onSelectionChanged(); void onXYChanged(); void onOrientationChanged(); + void onDistributionChanged( int ); private: SMESHGUI* mySMESHGUI; @@ -117,7 +120,14 @@ private: SMESHGUI_SpinBox* myWidthSpin; SMESHGUI_SpinBox* myHeightSpin; + QGroupBox* myDistributionGrp; + QRadioButton* myDMonoColor; + QRadioButton* myDMultiColor; + QtxColorButton* myMonoColorBtn; + QLabel* myDistributionColorLbl; + QGroupBox* myButtonGrp; + QButtonGroup* myDistribColorGrp; QPushButton* myOkBtn; QPushButton* myApplyBtn; QPushButton* myCancelBtn; diff --git a/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx b/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx index a007feb0f..3556398a1 100644 --- a/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx @@ -371,24 +371,24 @@ void SMESHGUI_RemoveElementsDlg::SelectionIntoArgument() myActor = SMESH::FindActorByEntry(anIO->getEntry()); if (myActor) { - - // get selected nodes - QString aString = ""; - int nbElems = SMESH::GetNameOfSelectedElements(mySelector,anIO,aString); - if (nbElems > 0) { - myBusy = true; - myEditCurrentArgument->setText(aString); - myBusy = false; - - // OK - - myNbOkElements = nbElems; - } // if (nbElems > 0) + + // get selected nodes + QString aString = ""; + int nbElems = SMESH::GetNameOfSelectedElements(mySelector,anIO,aString); + if (nbElems > 0) { + myBusy = true; + myEditCurrentArgument->setText(aString); + myBusy = false; + + // OK + + myNbOkElements = nbElems; + } // if (nbElems > 0) } // if (myActor) } // if (!myMesh->_is_nil()) } // if (nbSel == 1) { - updateButtons(); + updateButtons(); } //================================================================================= diff --git a/src/SMESHGUI/SMESHGUI_RemoveNodesDlg.cxx b/src/SMESHGUI/SMESHGUI_RemoveNodesDlg.cxx index 58fd31fb3..bd2ef2188 100644 --- a/src/SMESHGUI/SMESHGUI_RemoveNodesDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_RemoveNodesDlg.cxx @@ -377,23 +377,23 @@ void SMESHGUI_RemoveNodesDlg::SelectionIntoArgument() myActor = SMESH::FindActorByEntry(anIO->getEntry()); if (myActor) { - // get selected nodes - QString aString = ""; - int nbNodes = SMESH::GetNameOfSelectedNodes(mySelector,anIO,aString); - if (nbNodes > 0) { - myBusy = true; - myEditCurrentArgument->setText(aString); - myBusy = false; - - // OK - - myNbOkNodes = nbNodes; - } // if (nbNodes > 0) + // get selected nodes + QString aString = ""; + int nbNodes = SMESH::GetNameOfSelectedNodes(mySelector,anIO,aString); + if (nbNodes > 0) { + myBusy = true; + myEditCurrentArgument->setText(aString); + myBusy = false; + + // OK + + myNbOkNodes = nbNodes; + } // if (nbNodes > 0) } // if (myActor) } // if (!myMesh->_is_nil()) } // if (nbSel == 1) - updateButtons(); + updateButtons(); } //================================================================================= diff --git a/src/SMESHGUI/SMESHGUI_RotationDlg.cxx b/src/SMESHGUI/SMESHGUI_RotationDlg.cxx index 1dc48b0b3..7e2f2af84 100644 --- a/src/SMESHGUI/SMESHGUI_RotationDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_RotationDlg.cxx @@ -19,12 +19,11 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_RotationDlg.cxx +// Author : Michael ZORIN, Open CASCADE S.A.S. +// SMESH includes -// SMESH SMESHGUI : GUI for SMESH component -// File : SMESHGUI_RotationDlg.cxx -// Author : Michael ZORIN, Open CASCADE S.A.S. -// SMESH includes -// #include "SMESHGUI_RotationDlg.h" #include "SMESHGUI.h" @@ -84,6 +83,10 @@ enum { MOVE_ELEMS_BUTTON = 0, COPY_ELEMS_BUTTON, MAKE_MESH_BUTTON }; //!< action #define SPACING 8 #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 + //================================================================================= // class : SMESHGUI_RotationDlg() // purpose : @@ -430,22 +433,31 @@ bool SMESHGUI_RotationDlg::ClickOnApply() else { if(CheckBoxMesh->isChecked()) aMeshEditor->RotateObject(mySelectedObject, anAxis, anAngle, true); - else + else aMeshEditor->Rotate(anElementsId, anAxis, anAngle, true); } if( !myMesh->_is_nil()) myMesh->SetParameters( aParameters.join(":").toLatin1().constData() ); break; - case MAKE_MESH_BUTTON: + case MAKE_MESH_BUTTON: { SMESH::SMESH_Mesh_var mesh; - if(CheckBoxMesh->isChecked()) + if (CheckBoxMesh->isChecked()) mesh = aMeshEditor->RotateObjectMakeMesh(mySelectedObject, anAxis, anAngle, makeGroups, LineEditNewMesh->text().toLatin1().data()); - else + else mesh = aMeshEditor->RotateMakeMesh(anElementsId, anAxis, anAngle, makeGroups, LineEditNewMesh->text().toLatin1().data()); - if( !mesh->_is_nil()) - mesh->SetParameters( aParameters.join(":").toLatin1().constData() ); + if (!mesh->_is_nil()) { + mesh->SetParameters(aParameters.join(":").toLatin1().constData()); +#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 + mesh->Destroy(); +#endif + } + break; + } } } catch (...) { } @@ -500,7 +512,7 @@ void SMESHGUI_RotationDlg::ClickOnCancel() void SMESHGUI_RotationDlg::ClickOnHelp() { 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; @@ -542,9 +554,9 @@ void SMESHGUI_RotationDlg::onTextChange (const QString& theNewText) if (aMesh) { if (send == LineEditElements) { Handle(SALOME_InteractiveObject) anIO = myActor->getIO(); - + TColStd_MapOfInteger newIndices; - + QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts); for (int i = 0; i < aListId.count(); i++) { const SMDS_MeshElement * e = aMesh->FindElement(aListId[ i ].toInt()); @@ -556,7 +568,7 @@ void SMESHGUI_RotationDlg::onTextChange (const QString& theNewText) mySelector->AddOrRemoveIndex( anIO, newIndices, false ); if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->highlight( anIO, true, true ); - + myElementsId = theNewText; } } @@ -649,7 +661,7 @@ void SMESHGUI_RotationDlg::SelectionIntoArgument() } else if (!SMESH::IObjectToInterface(IO)->_is_nil()) { //SUBMESH // get submesh SMESH::SMESH_subMesh_var aSubMesh = SMESH::IObjectToInterface(IO); - + // get IDs from submesh SMESH::long_array_var anElementsIds = new SMESH::long_array; anElementsIds = aSubMesh->GetElementsId(); @@ -715,7 +727,7 @@ void SMESHGUI_RotationDlg::SelectionIntoArgument() LineEditElements->setText(aString); LineEditElements->repaint(); LineEditElements->setEnabled(false); // to update lineedit IPAL 19809 - LineEditElements->setEnabled(true); + LineEditElements->setEnabled(true); setNewMeshName(); } myBusy = false; diff --git a/src/SMESHGUI/SMESHGUI_ScaleDlg.cxx b/src/SMESHGUI/SMESHGUI_ScaleDlg.cxx index b9a5c1a0b..fc275baaa 100644 --- a/src/SMESHGUI/SMESHGUI_ScaleDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ScaleDlg.cxx @@ -16,12 +16,11 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_ScaleDlg.cxx +// Author : Michael ZORIN, Open CASCADE S.A.S. +// SMESH includes -// SMESH SMESHGUI : GUI for SMESH component -// File : SMESHGUI_ScaleDlg.cxx -// Author : Michael ZORIN, Open CASCADE S.A.S. -// SMESH includes -// #include "SMESHGUI_ScaleDlg.h" #include "SMESHGUI.h" @@ -99,6 +98,10 @@ private: #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 + //================================================================================= // class : SMESHGUI_ScaleDlg() // purpose : @@ -467,58 +470,49 @@ bool SMESHGUI_ScaleDlg::ClickOnApply() try { SUIT_OverrideCursor aWaitCursor; SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor(); + SMESH::SMESH_IDSource_var obj; + if ( CheckBoxMesh->isChecked() ) + obj = mySelectedObject; + else + obj = aMeshEditor->MakeIDSource(anElementsId, SMESH::ALL); + switch ( actionButton ) { + case MOVE_ELEMS_BUTTON: - if(CheckBoxMesh->isChecked()) { - aMeshEditor->Scale(mySelectedObject, aPoint, aScaleFact, false); - } - else { - SMESH::SMESH_IDSource_ptr anObj = aMeshEditor->MakeIDSource(anElementsId); - aMeshEditor->Scale(anObj, aPoint, aScaleFact, false); - } + aMeshEditor->Scale(obj, aPoint, aScaleFact, false); if( !myMesh->_is_nil()) myMesh->SetParameters( aParameters.join(":").toLatin1().constData() ); break; + case COPY_ELEMS_BUTTON: - if ( makeGroups ) { - SMESH::ListOfGroups_var groups; - if(CheckBoxMesh->isChecked()) { - groups = aMeshEditor->ScaleMakeGroups(mySelectedObject, aPoint, aScaleFact); - } - else { - groups = aMeshEditor->ScaleMakeGroups(aMeshEditor->MakeIDSource(anElementsId), - aPoint, aScaleFact); - } - } - else { - if(CheckBoxMesh->isChecked()) { - aMeshEditor->Scale(mySelectedObject, aPoint, aScaleFact, true); - } - else { - aMeshEditor->Scale(aMeshEditor->MakeIDSource(anElementsId), - aPoint, aScaleFact, true); - } - } + if ( makeGroups ) + SMESH::ListOfGroups_var groups = + aMeshEditor->ScaleMakeGroups(obj, aPoint, aScaleFact); + else + aMeshEditor->Scale(obj, aPoint, aScaleFact, true); if( !myMesh->_is_nil()) myMesh->SetParameters( aParameters.join(":").toLatin1().constData() ); break; - case MAKE_MESH_BUTTON: - SMESH::SMESH_Mesh_var mesh; - if(CheckBoxMesh->isChecked()) { - mesh = aMeshEditor->ScaleMakeMesh(mySelectedObject, aPoint, aScaleFact, makeGroups, - LineEditNewMesh->text().toLatin1().data()); - } - else { - mesh = aMeshEditor->ScaleMakeMesh(aMeshEditor->MakeIDSource(anElementsId), - aPoint, aScaleFact, makeGroups, - LineEditNewMesh->text().toLatin1().data()); + + case MAKE_MESH_BUTTON: { + SMESH::SMESH_Mesh_var mesh = + aMeshEditor->ScaleMakeMesh(obj, aPoint, aScaleFact, makeGroups, + LineEditNewMesh->text().toLatin1().data()); + if (!mesh->_is_nil()) { + mesh->SetParameters(aParameters.join(":").toLatin1().constData()); +#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 + mesh->Destroy(); +#endif } - if( !mesh->_is_nil()) - mesh->SetParameters( aParameters.join(":").toLatin1().constData() ); + break; + } } } catch (...) { } - + SMESH::UpdateView(); if ( MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked() || actionButton == MAKE_MESH_BUTTON ) @@ -530,7 +524,7 @@ bool SMESHGUI_ScaleDlg::ClickOnApply() SMESHGUI::Modified(); } - + return true; } @@ -570,7 +564,7 @@ void SMESHGUI_ScaleDlg::ClickOnCancel() void SMESHGUI_ScaleDlg::ClickOnHelp() { 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; @@ -581,7 +575,7 @@ void SMESHGUI_ScaleDlg::ClickOnHelp() #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)); } @@ -611,7 +605,7 @@ void SMESHGUI_ScaleDlg::onTextChange (const QString& theNewText) if (aMesh) { Handle(SALOME_InteractiveObject) anIO = myActor->getIO(); - + TColStd_MapOfInteger newIndices; QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts); @@ -628,7 +622,7 @@ void SMESHGUI_ScaleDlg::onTextChange (const QString& theNewText) mySelector->AddOrRemoveIndex( anIO, newIndices, false ); if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->highlight( anIO, true, true ); - + myElementsId = theNewText; } @@ -745,7 +739,7 @@ void SMESHGUI_ScaleDlg::SelectionIntoArgument() aNbUnits = SMESH::GetNameOfSelectedElements(mySelector, IO, aString); myElementsId = aString; if (aNbUnits < 1) - return; + return; } myNbOkElements = true; @@ -782,7 +776,7 @@ void SMESHGUI_ScaleDlg::SelectionIntoArgument() LineEditElements->setText(aString); LineEditElements->repaint(); LineEditElements->setEnabled(false); // to fully update lineedit IPAL 19809 - LineEditElements->setEnabled(true); + LineEditElements->setEnabled(true); setNewMeshName(); } diff --git a/src/SMESHGUI/SMESHGUI_Selection.cxx b/src/SMESHGUI/SMESHGUI_Selection.cxx index 887cdea08..df7c9c1c6 100644 --- a/src/SMESHGUI/SMESHGUI_Selection.cxx +++ b/src/SMESHGUI/SMESHGUI_Selection.cxx @@ -34,6 +34,7 @@ #include #include +#include // SALOME GUI includes #include @@ -114,6 +115,7 @@ QVariant SMESHGUI_Selection::parameter( const int ind, const QString& p ) const else if ( p=="shrinkMode" ) val = QVariant( shrinkMode( ind ) ); else if ( p=="entityMode" ) val = QVariant( entityMode( ind ) ); else if ( p=="controlMode" ) val = QVariant( controlMode( ind ) ); + else if ( p=="isNumFunctor" ) val = QVariant( isNumFunctor( ind ) ); else if ( p=="displayMode" ) val = QVariant( displayMode( ind ) ); else if ( p=="isComputable" ) val = QVariant( isComputable( ind ) ); else if ( p=="isPreComputable" ) val = QVariant( isPreComputable( ind ) ); @@ -122,6 +124,7 @@ QVariant SMESHGUI_Selection::parameter( const int ind, const QString& p ) const else if ( p=="facesOrientationMode" ) val = QVariant( facesOrientationMode( ind ) ); else if ( p=="groupType" ) val = QVariant( groupType( ind ) ); else if ( p=="quadratic2DMode") val = QVariant(quadratic2DMode(ind)); + else if ( p=="isDistributionVisible") val = QVariant(isDistributionVisible(ind)); if( val.isValid() ) return val; @@ -216,6 +219,16 @@ QString SMESHGUI_Selection::quadratic2DMode( int ind ) const return "Unknown"; } +//======================================================================= +//function : isDistributionVisible +//purpose : Visible/Invisible distribution of the ScalarBar Actor +//======================================================================= + +bool SMESHGUI_Selection::isDistributionVisible(int ind) const { + SMESH_Actor* actor = getActor( ind ); + return (actor && actor->GetScalarBarActor() && actor->GetScalarBarActor()->GetDistributionVisibility()); +} + //======================================================================= //function : shrinkMode //purpose : return either 'IsSrunk', 'IsNotShrunk' or 'IsNotShrinkable' @@ -271,6 +284,8 @@ QString SMESHGUI_Selection::controlMode( int ind ) const case SMESH_Actor::eMultiConnection2D: return "eMultiConnection2D"; case SMESH_Actor::eArea: return "eArea"; case SMESH_Actor::eVolume3D: return "eVolume3D"; + case SMESH_Actor::eMaxElementLength2D: return "eMaxElementLength2D"; + case SMESH_Actor::eMaxElementLength3D: return "eMaxElementLength3D"; case SMESH_Actor::eTaper: return "eTaper"; case SMESH_Actor::eAspectRatio: return "eAspectRatio"; case SMESH_Actor::eAspectRatio3D: return "eAspectRatio3D"; @@ -283,6 +298,35 @@ QString SMESHGUI_Selection::controlMode( int ind ) const return "eNone"; } +bool SMESHGUI_Selection::isNumFunctor( int ind ) const +{ + bool result = false; + SMESH_Actor* actor = getActor( ind ); + if ( actor ) { + switch( actor->GetControlMode() ) { + case SMESH_Actor::eLength: + case SMESH_Actor::eLength2D: + case SMESH_Actor::eMultiConnection: + case SMESH_Actor::eMultiConnection2D: + case SMESH_Actor::eArea: + case SMESH_Actor::eVolume3D: + case SMESH_Actor::eMaxElementLength2D: + case SMESH_Actor::eMaxElementLength3D: + case SMESH_Actor::eTaper: + case SMESH_Actor::eAspectRatio: + case SMESH_Actor::eAspectRatio3D: + case SMESH_Actor::eMinimumAngle: + case SMESH_Actor::eWarping: + case SMESH_Actor::eSkew: + result = true; + break; + default: + break; + } + } + return result; +} + //======================================================================= //function : facesOrientationMode //purpose : @@ -590,4 +634,3 @@ QString SMESHGUI_Selection::groupType( int ind ) const } return type; } - diff --git a/src/SMESHGUI/SMESHGUI_Selection.h b/src/SMESHGUI/SMESHGUI_Selection.h index 2320041de..2ad545d98 100644 --- a/src/SMESHGUI/SMESHGUI_Selection.h +++ b/src/SMESHGUI/SMESHGUI_Selection.h @@ -61,6 +61,8 @@ public: virtual QString quadratic2DMode(int ) const; + virtual bool isDistributionVisible(int ) const; + // parameters got from actor return nothing if an actor is not visible virtual QList elemTypes( int ) const; virtual QList labeledTypes( int ) const; @@ -68,6 +70,7 @@ public: virtual QString shrinkMode( int ) const; virtual QList entityMode( int ) const; virtual QString controlMode( int ) const; + virtual bool isNumFunctor( int ) const; virtual QString facesOrientationMode( int ) const; virtual QString groupType( int ) const; diff --git a/src/SMESHGUI/SMESHGUI_SpinBox.cxx b/src/SMESHGUI/SMESHGUI_SpinBox.cxx index d34f9f8d7..03d53d830 100644 --- a/src/SMESHGUI/SMESHGUI_SpinBox.cxx +++ b/src/SMESHGUI/SMESHGUI_SpinBox.cxx @@ -66,7 +66,7 @@ void SMESHGUI_SpinBox::SetStep( double newStep ) //================================================================================= void SMESHGUI_SpinBox::SetValue( double v ) { - setValue(v); + setValue(valueFromText(textFromValue(v))); editor()->setCursorPosition( 0 ); } @@ -113,7 +113,7 @@ void SMESHGUI_SpinBox::RangeStepAndValidator( double min, setPrecision(precision); // PAL8769. Minus is for using 'g' double->string conversion specifier, // see QtxDoubleSpinBox::mapValueToText( double v ) // san: this can be achieved using preferences - setDecimals(qAbs(precision)); + setDecimals( 20 ); // qAbs(precision) setRange(min, max); setSingleStep( step ); setDefaultValue( min ); diff --git a/src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx b/src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx index 2a3562e3d..138235888 100644 --- a/src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx @@ -19,12 +19,11 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_SymmetryDlg.cxx +// Author : Michael ZORIN, Open CASCADE S.A.S. +// SMESH includes -// SMESH SMESHGUI : GUI for SMESH component -// File : SMESHGUI_SymmetryDlg.cxx -// Author : Michael ZORIN, Open CASCADE S.A.S. -// SMESH includes -// #include "SMESHGUI_SymmetryDlg.h" #include "SMESHGUI.h" @@ -84,6 +83,10 @@ enum { MOVE_ELEMS_BUTTON = 0, COPY_ELEMS_BUTTON, MAKE_MESH_BUTTON }; //!< action #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 + //================================================================================= // class : SMESHGUI_SymmetryDlg() // purpose : @@ -500,7 +503,7 @@ bool SMESHGUI_SymmetryDlg::ClickOnApply() aMeshEditor->MirrorObject(mySelectedObject, aMirror, aMirrorType, false ); else aMeshEditor->Mirror(anElementsId, aMirror, aMirrorType, false ); - + if( !myMesh->_is_nil()) myMesh->SetParameters( aParameters.join(":").toLatin1().constData() ); break; @@ -525,20 +528,27 @@ bool SMESHGUI_SymmetryDlg::ClickOnApply() } case MAKE_MESH_BUTTON: { SMESH::SMESH_Mesh_var mesh; - if(CheckBoxMesh->isChecked()) + if (CheckBoxMesh->isChecked()) mesh = aMeshEditor->MirrorObjectMakeMesh(mySelectedObject, aMirror, aMirrorType, makeGroups, LineEditNewMesh->text().toLatin1().data()); else mesh = aMeshEditor->MirrorMakeMesh(anElementsId, aMirror, aMirrorType, makeGroups, LineEditNewMesh->text().toLatin1().data()); - if( !mesh->_is_nil()) - mesh->SetParameters( aParameters.join(":").toLatin1().constData() ); + if (!mesh->_is_nil()) { + mesh->SetParameters(aParameters.join(":").toLatin1().constData()); +#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 + mesh->Destroy(); +#endif + } break; } } } catch (...) { } - + SMESH::UpdateView(); if ( MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked() || actionButton == MAKE_MESH_BUTTON ) @@ -589,7 +599,7 @@ void SMESHGUI_SymmetryDlg::ClickOnCancel() void SMESHGUI_SymmetryDlg::ClickOnHelp() { 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; @@ -632,7 +642,7 @@ void SMESHGUI_SymmetryDlg::onTextChange (const QString& theNewText) Handle(SALOME_InteractiveObject) anIO = myActor->getIO(); TColStd_MapOfInteger newIndices; - + QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts); if (send == LineEditElements) { @@ -646,7 +656,7 @@ void SMESHGUI_SymmetryDlg::onTextChange (const QString& theNewText) mySelector->AddOrRemoveIndex( anIO, newIndices, false ); if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->highlight( anIO, true, true ); - + myElementsId = theNewText; } } @@ -736,7 +746,6 @@ void SMESHGUI_SymmetryDlg::SelectionIntoArgument() aNbUnits++; } } - } else if (!SMESH::IObjectToInterface(IO)->_is_nil()) { //SUBMESH // get submesh SMESH::SMESH_subMesh_var aSubMesh = SMESH::IObjectToInterface(IO); @@ -749,7 +758,6 @@ void SMESHGUI_SymmetryDlg::SelectionIntoArgument() myElementsId += QString(" %1").arg(anElementsIds[i]); } aNbUnits = anElementsIds->length(); - } else { // GROUP // get smesh group SMESH::SMESH_GroupBase_var aGroup = @@ -772,7 +780,7 @@ void SMESHGUI_SymmetryDlg::SelectionIntoArgument() if (aNbUnits < 1) return; } - + myNbOkElements = true; } else { aNbUnits = SMESH::GetNameOfSelectedNodes(mySelector, IO, aString); @@ -807,7 +815,7 @@ void SMESHGUI_SymmetryDlg::SelectionIntoArgument() LineEditElements->setText(aString); LineEditElements->repaint(); LineEditElements->setEnabled(false); // to update lineedit IPAL 19809 - LineEditElements->setEnabled(true); + LineEditElements->setEnabled(true); setNewMeshName(); } myBusy = false; diff --git a/src/SMESHGUI/SMESHGUI_TranslationDlg.cxx b/src/SMESHGUI/SMESHGUI_TranslationDlg.cxx index fac987991..14a5866e0 100644 --- a/src/SMESHGUI/SMESHGUI_TranslationDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_TranslationDlg.cxx @@ -19,12 +19,11 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_TranslationDlg.cxx +// Author : Michael ZORIN, Open CASCADE S.A.S. +// SMESH includes -// SMESH SMESHGUI : GUI for SMESH component -// File : SMESHGUI_TranslationDlg.cxx -// Author : Michael ZORIN, Open CASCADE S.A.S. -// SMESH includes -// #include "SMESHGUI_TranslationDlg.h" #include "SMESHGUI.h" @@ -102,6 +101,10 @@ private: #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 + //================================================================================= // class : SMESHGUI_TranslationDlg() // purpose : @@ -494,7 +497,7 @@ bool SMESHGUI_TranslationDlg::ClickOnApply() break; case COPY_ELEMS_BUTTON: if ( makeGroups ) { - SMESH::ListOfGroups_var groups; + SMESH::ListOfGroups_var groups; if(CheckBoxMesh->isChecked()) groups = aMeshEditor->TranslateObjectMakeGroups(mySelectedObject,aVector); else @@ -510,19 +513,26 @@ bool SMESHGUI_TranslationDlg::ClickOnApply() myMesh->SetParameters( aParameters.join(":").toLatin1().constData() ); break; case MAKE_MESH_BUTTON: - SMESH::SMESH_Mesh_var mesh; - if(CheckBoxMesh->isChecked()) + SMESH::SMESH_Mesh_var mesh; + if (CheckBoxMesh->isChecked()) mesh = aMeshEditor->TranslateObjectMakeMesh(mySelectedObject, aVector, makeGroups, LineEditNewMesh->text().toLatin1().data()); else mesh = aMeshEditor->TranslateMakeMesh(anElementsId, aVector, makeGroups, LineEditNewMesh->text().toLatin1().data()); - if( !mesh->_is_nil()) - mesh->SetParameters( aParameters.join(":").toLatin1().constData() ); + if (!mesh->_is_nil()) { + mesh->SetParameters(aParameters.join(":").toLatin1().constData()); +#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 + mesh->Destroy(); +#endif + } } } catch (...) { } - + SMESH::UpdateView(); if ( MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked() || actionButton == MAKE_MESH_BUTTON ) @@ -534,7 +544,7 @@ bool SMESHGUI_TranslationDlg::ClickOnApply() SMESHGUI::Modified(); } - + return true; } @@ -574,7 +584,7 @@ void SMESHGUI_TranslationDlg::ClickOnCancel() void SMESHGUI_TranslationDlg::ClickOnHelp() { 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; @@ -585,7 +595,7 @@ void SMESHGUI_TranslationDlg::ClickOnHelp() #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)); } @@ -615,7 +625,7 @@ void SMESHGUI_TranslationDlg::onTextChange (const QString& theNewText) if (aMesh) { Handle(SALOME_InteractiveObject) anIO = myActor->getIO(); - + TColStd_MapOfInteger newIndices; QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts); @@ -632,7 +642,7 @@ void SMESHGUI_TranslationDlg::onTextChange (const QString& theNewText) mySelector->AddOrRemoveIndex( anIO, newIndices, false ); if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->highlight( anIO, true, true ); - + myElementsId = theNewText; } @@ -750,7 +760,7 @@ void SMESHGUI_TranslationDlg::SelectionIntoArgument() aNbUnits = SMESH::GetNameOfSelectedElements(mySelector, IO, aString); myElementsId = aString; if (aNbUnits < 1) - return; + return; } myNbOkElements = true; @@ -786,7 +796,7 @@ void SMESHGUI_TranslationDlg::SelectionIntoArgument() LineEditElements->setText(aString); LineEditElements->repaint(); LineEditElements->setEnabled(false); // to fully update lineedit IPAL 19809 - LineEditElements->setEnabled(true); + LineEditElements->setEnabled(true); setNewMeshName(); } diff --git a/src/SMESHGUI/SMESHGUI_Utils.cxx b/src/SMESHGUI/SMESHGUI_Utils.cxx index 6f921cd22..dfe778831 100644 --- a/src/SMESHGUI/SMESHGUI_Utils.cxx +++ b/src/SMESHGUI/SMESHGUI_Utils.cxx @@ -205,6 +205,20 @@ namespace SMESH return SObjectToObject(theSObject,aStudy); } + _PTR(SObject) ObjectToSObject( CORBA::Object_ptr theObject ) + { + _PTR(SObject) res; + SalomeApp_Application* app = dynamic_cast + (SUIT_Session::session()->activeApplication()); + if ( app ) { + QString IOR = app->orb()->object_to_string( theObject ); + SalomeApp_Study* study = dynamic_cast( app->activeStudy() ); + if ( study && !IOR.isEmpty() ) + res = study->studyDS()->FindObjectIOR( IOR.toLatin1().constData() ); + } + return res; + } + CORBA::Object_var IObjectToObject (const Handle(SALOME_InteractiveObject)& theIO) { if (!theIO.IsNull()) { diff --git a/src/SMESHGUI/SMESHGUI_Utils.h b/src/SMESHGUI/SMESHGUI_Utils.h index 555d23382..996a34761 100644 --- a/src/SMESHGUI/SMESHGUI_Utils.h +++ b/src/SMESHGUI/SMESHGUI_Utils.h @@ -129,6 +129,9 @@ SMESHGUI_EXPORT return TInterface::_nil(); } +SMESHGUI_EXPORT + _PTR(SObject) ObjectToSObject( CORBA::Object_ptr ); + SMESHGUI_EXPORT CORBA::Object_var IObjectToObject( const Handle(SALOME_InteractiveObject)& ); diff --git a/src/SMESHGUI/SMESHGUI_VTKUtils.cxx b/src/SMESHGUI/SMESHGUI_VTKUtils.cxx index e210f2c7f..c663c74da 100644 --- a/src/SMESHGUI/SMESHGUI_VTKUtils.cxx +++ b/src/SMESHGUI/SMESHGUI_VTKUtils.cxx @@ -65,6 +65,7 @@ #include CORBA_CLIENT_HEADER(SMESH_Group) // VTK includes +#include #include #include #include @@ -204,13 +205,16 @@ namespace SMESH } } TVisualObjCont::iterator anIter = VISUAL_OBJ_CONT.begin(); - for ( ; anIter != VISUAL_OBJ_CONT.end(); ++anIter ) { + for ( ; anIter != VISUAL_OBJ_CONT.end(); ) { int curId = anIter->first.first; if ( curId == studyID ) { // for unknown reason, object destructor is not called, so clear object manually anIter->second->GetUnstructuredGrid()->SetCells(0,0,0); anIter->second->GetUnstructuredGrid()->SetPoints(0); - VISUAL_OBJ_CONT.erase( anIter-- ); // dercement occures before erase() + VISUAL_OBJ_CONT.erase( anIter++ ); // anIter++ returns a copy of self before incrementing + } + else { + anIter++; } } } @@ -602,6 +606,9 @@ namespace SMESH } } } + if( anActor ) + if( SMESHGUI* aSMESHGUI = SMESHGUI::GetSMESHGUI() ) + aSMESHGUI->addActorAsObserver( anActor ); return anActor; } @@ -1164,4 +1171,108 @@ namespace SMESH } } + + //---------------------------------------------------------------------------- + // internal function + void ComputeBoundsParam( vtkFloatingPointType theBounds[6], + vtkFloatingPointType theDirection[3], + vtkFloatingPointType theMinPnt[3], + vtkFloatingPointType& theMaxBoundPrj, + vtkFloatingPointType& theMinBoundPrj ) + { + //Enlarge bounds in order to avoid conflicts of precision + for(int i = 0; i < 6; i += 2){ + static double EPS = 1.0E-3; + vtkFloatingPointType aDelta = (theBounds[i+1] - theBounds[i])*EPS; + theBounds[i] -= aDelta; + theBounds[i+1] += aDelta; + } + + vtkFloatingPointType aBoundPoints[8][3] = { {theBounds[0],theBounds[2],theBounds[4]}, + {theBounds[1],theBounds[2],theBounds[4]}, + {theBounds[0],theBounds[3],theBounds[4]}, + {theBounds[1],theBounds[3],theBounds[4]}, + {theBounds[0],theBounds[2],theBounds[5]}, + {theBounds[1],theBounds[2],theBounds[5]}, + {theBounds[0],theBounds[3],theBounds[5]}, + {theBounds[1],theBounds[3],theBounds[5]}}; + + int aMaxId = 0, aMinId = aMaxId; + theMaxBoundPrj = vtkMath::Dot(theDirection,aBoundPoints[aMaxId]); + theMinBoundPrj = theMaxBoundPrj; + for(int i = 1; i < 8; i++){ + vtkFloatingPointType aTmp = vtkMath::Dot(theDirection,aBoundPoints[i]); + if(theMaxBoundPrj < aTmp){ + theMaxBoundPrj = aTmp; + aMaxId = i; + } + if(theMinBoundPrj > aTmp){ + theMinBoundPrj = aTmp; + aMinId = i; + } + } + vtkFloatingPointType *aMinPnt = aBoundPoints[aMaxId]; + theMinPnt[0] = aMinPnt[0]; + theMinPnt[1] = aMinPnt[1]; + theMinPnt[2] = aMinPnt[2]; + } + + // internal function + void DistanceToPosition( vtkFloatingPointType theBounds[6], + vtkFloatingPointType theDirection[3], + vtkFloatingPointType theDist, + vtkFloatingPointType thePos[3] ) + { + vtkFloatingPointType aMaxBoundPrj, aMinBoundPrj, aMinPnt[3]; + ComputeBoundsParam(theBounds,theDirection,aMinPnt,aMaxBoundPrj,aMinBoundPrj); + vtkFloatingPointType aLength = (aMaxBoundPrj-aMinBoundPrj)*theDist; + thePos[0] = aMinPnt[0]-theDirection[0]*aLength; + thePos[1] = aMinPnt[1]-theDirection[1]*aLength; + thePos[2] = aMinPnt[2]-theDirection[2]*aLength; + } + + // internal function (currently unused, left just in case) + void PositionToDistance( vtkFloatingPointType theBounds[6], + vtkFloatingPointType theDirection[3], + vtkFloatingPointType thePos[3], + vtkFloatingPointType& theDist ) + { + vtkFloatingPointType aMaxBoundPrj, aMinBoundPrj, aMinPnt[3]; + ComputeBoundsParam(theBounds,theDirection,aMinPnt,aMaxBoundPrj,aMinBoundPrj); + vtkFloatingPointType aPrj = vtkMath::Dot(theDirection,thePos); + theDist = (aPrj-aMinBoundPrj)/(aMaxBoundPrj-aMinBoundPrj); + } + + bool ComputeClippingPlaneParameters( std::list theActorList, + vtkFloatingPointType theNormal[3], + vtkFloatingPointType theDist, + vtkFloatingPointType theBounds[6], + vtkFloatingPointType theOrigin[3] ) + { + bool anIsOk = false; + theBounds[0] = theBounds[2] = theBounds[4] = VTK_DOUBLE_MAX; + theBounds[1] = theBounds[3] = theBounds[5] = -VTK_DOUBLE_MAX; + std::list::iterator anIter = theActorList.begin(); + for( ; anIter != theActorList.end(); anIter++ ) { + if( vtkActor* aVTKActor = *anIter ) { + if( SMESH_Actor* anActor = SMESH_Actor::SafeDownCast( aVTKActor ) ) { + vtkFloatingPointType aBounds[6]; + anActor->GetUnstructuredGrid()->GetBounds( aBounds ); + theBounds[0] = std::min( theBounds[0], aBounds[0] ); + theBounds[1] = std::max( theBounds[1], aBounds[1] ); + theBounds[2] = std::min( theBounds[2], aBounds[2] ); + theBounds[3] = std::max( theBounds[3], aBounds[3] ); + theBounds[4] = std::min( theBounds[4], aBounds[4] ); + theBounds[5] = std::max( theBounds[5], aBounds[5] ); + anIsOk = true; + } + } + } + + if( !anIsOk ) + return false; + + DistanceToPosition( theBounds, theNormal, theDist, theOrigin ); + return true; + } } // end of namespace SMESH diff --git a/src/SMESHGUI/SMESHGUI_VTKUtils.h b/src/SMESHGUI/SMESHGUI_VTKUtils.h index 508ce767e..5a9b09c25 100644 --- a/src/SMESHGUI/SMESHGUI_VTKUtils.h +++ b/src/SMESHGUI/SMESHGUI_VTKUtils.h @@ -57,6 +57,8 @@ class SMESHGUI; class SMESH_Actor; class SALOME_Actor; +class vtkActor; + namespace SMESH { //---------------------------------------------------------------------------- @@ -185,6 +187,14 @@ SMESHGUI_EXPORT SMESHGUI_EXPORT void SetControlsPrecision( const long ); + + //---------------------------------------------------------------------------- +SMESHGUI_EXPORT + bool ComputeClippingPlaneParameters( std::list theActorList, + vtkFloatingPointType theNormal[3], + vtkFloatingPointType theDist, + vtkFloatingPointType theBounds[6], + vtkFloatingPointType theOrigin[3] ); }; #endif // SMESHGUI_VTKUTILS_H diff --git a/src/SMESHGUI/SMESH_images.ts b/src/SMESHGUI/SMESH_images.ts index 22b3fd7e8..856e88f32 100644 --- a/src/SMESHGUI/SMESH_images.ts +++ b/src/SMESHGUI/SMESH_images.ts @@ -205,6 +205,10 @@ ICON_DLG_REM_NODE mesh_rem_node.png + + ICON_DLG_REM_ORPHAN_NODES + mesh_rem_orphan_nodes.png + ICON_DLG_RENUMBERING_ELEMENTS mesh_renumbering_elements.png @@ -285,6 +289,14 @@ ICON_MAP mesh_pattern.png + + ICON_MAX_ELEMENT_LENGTH_2D + mesh_max_element_length_2d.png + + + ICON_MAX_ELEMENT_LENGTH_3D + mesh_max_element_length_3d.png + ICON_OBJBROWSER_SMESH mesh.png @@ -381,6 +393,14 @@ ICON_DLG_SCALE_ALONG_AXES scale_along_axes.png + + ICON_SMESH_DUPLICATE_NODES + mesh_duplicate_nodes.png + + + ICON_SMESH_DUPLICATE_NODES_WITH_ELEM + mesh_duplicate_nodes_with_elem.png + ICON_SMESH_TREE_ALGO mesh_tree_algo.png @@ -443,7 +463,7 @@ ICON_WHAT_IS - mesh_whatis.png + mesh_elem_info.png ICON_WIRE @@ -465,5 +485,13 @@ ICON_SPLIT_TO_TETRA split_into_tetra.png + + ICON_MEASURE_MIN_DIST + mesh_min_dist.png + + + ICON_MEASURE_BND_BOX + mesh_bounding_box.png + diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index 790b7c1a8..81e2619ee 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -1,5194 +1,5904 @@ + - - - - @default - - AREA_ELEMENTS - Area - - - ASPECTRATIO_3D_ELEMENTS - Aspect Ratio 3D - - - ASPECTRATIO_ELEMENTS - Aspect Ratio - - - COL_ALGO_HEADER - Algorithm - - - COL_ERROR_HEADER - Error - - - COL_SHAPE_HEADER - SubShape - - - COMPERR_ALGO_FAILED - Algorithm failed - - - COMPERR_BAD_INPUT_MESH - Invalid input mesh - - - COMPERR_BAD_SHAPE - Unexpected geometry - - - COMPERR_EXCEPTION - Unknown exception - - - COMPERR_MEMORY_PB - Memory allocation problem - - - COMPERR_OCC_EXCEPTION - OCC exception - - - COMPERR_OK - No errors - - - COMPERR_SLM_EXCEPTION - SALOME exception - - - COMPERR_STD_EXCEPTION - std::exception - - - SMESH_GEOM - Geometry - - - DIRECT_GEOM_SELECTION - Direct geometry selection - - - ELEMENT_ID - Element ID - - - FREE_BORDERS - Free Borders - - - GEOMETRY_NAME - Geometry name - - - GEOM_BY_MESH_ELEM_SELECTION - Find geometry by mesh element selection - - - GLOBAL_ALGO - Global - - - INF_SELECT_OBJECT - Select an object - - - LENGTH2D_EDGES - Length 2D - - - LENGTH_EDGES - Length - - - LOCAL_ALGO - Local - - - MEN_ADD - Add - - - MEN_ADV_INFO - Advanced Mesh Infos - - - MEN_ALL - All - - - MEN_AREA - Area - - - MEN_ASPECT - Aspect Ratio - - - MEN_ASPECT_3D - Aspect Ratio 3D - - - MEN_AUTO_COLOR - Auto Color - - - MEN_AUTO_UPD - Automatic Update - - - MEN_BUILD_COMPOUND - Build Compound - - - MEN_CLIP - Clipping - - - MEN_COLORS - Colors / Size - - - MEN_COMPUTE - Compute - - - MEN_PRECOMPUTE - Preview - - - MEN_EVALUATE - Evaluate - - - MEN_CONNECTION - Borders at Multi-Connection - - - MEN_CONNECTION_2D - Borders at Multi-Connection 2D - - - MEN_CONSTRUCT_GROUP - Construct Group - - - MEN_CONV_TO_QUAD - Convert to/from quadratic - - - MEN_2D_FROM_3D - Create 2D mesh from 3D - - - MEN_MESH_ORDER - Change submesh priority - - - MEN_CREATE_GROUP - Create Group - - - MEN_CREATE_GEO_GROUP - Create Groups from Geometry - - - MEN_CREATE_MESH - Create Mesh - - - MEN_CREATE_SUBMESH - Create Sub-mesh - - - MEN_CTRL - Controls - - - MEN_CUT - Cutting of Quadrangles - - - MEN_CUT_GROUP - Cut Groups - - - MEN_DAT - DAT File - - - MEN_DELETE - Delete - - - MEN_DEL_GROUP - Delete Groups - - - MEN_FACE_ORIENTATION - Orientation of Faces - - - MEN_DISABLE_AUTO_COLOR - Disable Auto Color - - - MEN_DISPLAY_ONLY - Show Only - - - MEN_DISPMODE - Display Mode - - - MEN_DISP_ENT - Display Entity - - - MEN_ELEM0D - 0D Element - - - MEN_ELEMS0D - 0D Elements - - - MEN_EDGE - Edge - - - MEN_EDGES - Edges - - - MEN_EDIT - Edit - - - MEN_EDIT_GROUP - Edit Group - - - MEN_EDIT_GEOMGROUP_AS_GROUP - Edit Group as Standalone - - - MEN_EDIT_HYPO - Edit Hypothesis - - - MEN_EDIT_MESHSUBMESH - Edit Mesh/Sub-mesh - - - MEN_EXPORT - Export - - - MEN_EXPORT_DAT - Export to DAT File - - - MEN_EXPORT_MED - Export to MED File - - - MEN_EXPORT_SAUV - Export to SAUV (ASCII) file - - - MEN_EXPORT_STL - Export to STL File - - - MEN_EXPORT_UNV - Export to UNV File - - - MEN_EXTRUSION - Extrusion - - - MEN_EXTRUSION_ALONG - Extrusion Along a Path - - - MEN_FACES - Faces - - - MEN_FILE - File - - - MEN_FIND_ELEM - Find Element by Point - - - TOP_FIND_ELEM - Find Element by Point - - - MEN_FREE_BORDER - Free Borders - - - MEN_FREE_EDGE - Free Edges - - - MEN_FREE_NODE - Free Nodes - - - MEN_FREE_FACES - Free Faces - - - MEN_GLOBAL_HYPO - Global Hypothesis - - - MEN_HEXA - Hexahedron - - - MEN_HIDE - Hide - - - MEN_HYPO - Hypotheses - - - MEN_IMPORT - Import - - - MEN_INT_GROUP - Intersect Groups - - - MEN_INV - Diagonal Inversion - - - MEN_LENGTH - Length - - - MEN_LENGTH_2D - Length 2D - - - MEN_MAP - Pattern Mapping - - - MEN_MED - MED file - - - MEN_SAUV - SAUV (ASCII) file - - - MEN_MERGE - Merge Nodes - - - MEN_MERGE_ELEMENTS - Merge Elements - - - - MEN_MESH - Mesh - - - MEN_MESH_THROU_POINT - Mesh to Pass Through a Point - - - MEN_MIN_ANG - Minimum Angle - - - MEN_MODIFY - Modification - - - MEN_MOVE - Move Node - - - MEN_NODE - Node - - - MEN_NODES - Nodes - - - MEN_NUM - Numbering - - - MEN_NUM_ELEMENTS - Display Elements # - - - MEN_NUM_NODES - Display Nodes # - - - MEN_ORIENT - Orientation - - - MEN_POLYGON - Polygon - - - MEN_POLYHEDRON - Polyhedron - - - MEN_PRECISION - Precision - - - MEN_PREF - Preferences - - - MEN_QUAD - Quadrangle - - - MEN_QUADRATIC_EDGE - Quadratic Edge - - - MEN_QUADRATIC_HEXAHEDRON - Quadratic Hexahedron - - - MEN_QUADRATIC_PENTAHEDRON - Quadratic Pentahedron - - - MEN_QUADRATIC_PYRAMID - Quadratic Pyramid - - - MEN_QUADRATIC_QUADRANGLE - Quadratic Quadrangle - - - MEN_QUADRATIC_TETRAHEDRON - Quadratic Tetrahedron - - - MEN_QUADRATIC_TRIANGLE - Quadratic Triangle - - - MEN_QUALITY - Quality Controls - - - MEN_REMOVE - Remove - - - MEN_REMOVE_ELEMENTS - Elements - - - MEN_REMOVE_NODES - Nodes - - - MEN_RENAME - Rename - - - MEN_RENUM - Renumbering - - - MEN_RENUM_ELEMENTS - Elements - - - MEN_RENUM_NODES - Nodes - - - MEN_RESET - Reset - - - MEN_REVOLUTION - Revolution - - - MEN_ROT - Rotation - - - MEN_SCALAR_BAR - Scalar Bar - - - MEN_SCALAR_BAR_PROP - Scalar Bar Properties - - - MEN_SELECTION - Selection - - - MEN_SEL_FILTER_LIB - Selection Filters Library - - - MEN_SEW - Sewing - - - MEN_SHADE - Shading - - - MEN_QUADRATIC_REPRESENT - 2D Quadratic - - - MEN_LINE_REPRESENTATION - Lines - - - MEN_ARC_REPRESENTATION - Arcs - - - MEN_SHOW - Show - - - MEN_SHRINK - Shrink - - - MEN_SKEW - Skew - - - MEN_SMOOTH - Smoothing - - - MEN_STD_INFO - Standard Mesh Infos - - - MEN_STL - STL File - - - MEN_SYM - Symmetry - - - MEN_TAPER - Taper - - - MEN_TETRA - Tetrahedron - - - MEN_TOOLS - Tools - - - MEN_TRANS - Translation - - - MEN_SCALE - Scale Transform - - - MEN_TRANSF - Transformation - - - MEN_TRANSP - Transparency - - - MEN_TRIANGLE - Triangle - - - MEN_UNASSIGN - Unassign - - - MEN_UNION - Union of Triangles - - - MEN_UNION2 - Union of Two Triangles - - - MEN_UNV - UNV File - - - MEN_UN_GROUP - Union Groups - - - MEN_UNDERLYING_ELEMS - Group of underlying entities - - - MEN_UPDATE - Update - - - MEN_VIEW - View - - - MEN_VOLUMES - Volumes - - - MEN_VOLUME_3D - Volume - - - MEN_WARP - Warping Angle - - - MEN_WHAT_IS - Mesh Element Info - - - MEN_WIRE - Wireframe - - - MEN_SPLIT_TO_TETRA - Split into Tetrahedra - - - TOP_SPLIT_TO_TETRA - Split into Tetrahedra - - - STB_SPLIT_TO_TETRA - Split into Tetrahedra - - - MESHERS_FILE_CANT_OPEN - Can not open resource file - - - MESHERS_FILE_CHECK_VARIABLE - Check environment variable SMESH_MeshersList - - - MESHERS_FILE_NO_VARIABLE - Environment variable SMESH_MeshersList is not defined - - - MESH_IS_NOT_SELECTED - There is no selected mesh -Please, select a mesh and try again - - - MESH_NODE - Node - - - MESH_NODE_TITLE - Add Node - - - MINIMUMANGLE_ELEMENTS - Minimum Angle - - - MULTI2D_BORDERS - Borders at Multi-Connections 2D - - - MULTI_BORDERS - Borders at Multi-Connections - - - GROUP_NAME_IS_EMPTY - Name of group is not specified. -Please enter a name of new group to be created or choose an existing one. - - - MESH_STANDALONE_GRP_CHOSEN - Group on geometry is chosen: %1. -Do you want to convert it to the standalone group? - - - NODE_ID - Node ID - - - NON_SMESH_OBJECTS_SELECTED - There are objects selected which do not belong to %1 component. - - - PREVIEW - Preview - - - SKEW_ELEMENTS - Skew - - - SMESHGUI_INVALID_PARAMETERS - Parameters are not correctly specified -Please enter correct values and try again - - - SMESH_ADD_ALGORITHM - Algorithms - - - SMESH_ADD_ALGORITHM_TITLE - Algorithms Assignation - - - SMESH_ADD_ELEM0D - Add 0D Element - - - SMESH_ADD_ELEM0D_TITLE - Add 0D Element - - - SMESH_ADD_EDGE - Add Edge - - - SMESH_ADD_EDGE_TITLE - Add Edge - - - SMESH_ADD_HEXAS - Add Hexahedron - - - SMESH_ADD_HEXAS_TITLE - Add Hexahedron - - - SMESH_ADD_HYPOTHESIS - Hypothesis - - - SMESH_ADD_HYPOTHESIS_TITLE - Hypothesis Assignation - - - SMESH_ADD_HYP_WRN - "%1" assigned but: - - - - SMESH_ADD_POLYGON - Add polygon - - - SMESH_ADD_POLYGON_TITLE - Add polygon - - - SMESH_ADD_QUADRANGLE - Add Quadrangle - - - SMESH_ADD_QUADRANGLE_TITLE - Add Quadrangle - - - SMESH_ADD_QUADRATIC_EDGE_TITLE - Add Quadratic Edge - - - SMESH_ADD_QUADRATIC_HEXAHEDRON_TITLE - Add Quadratic Hexahedron - - - SMESH_ADD_QUADRATIC_PENTAHEDRON_TITLE - Add Quadratic Pentahedron - - - SMESH_ADD_QUADRATIC_PYRAMID_TITLE - Add Quadratic Pyramid - - - SMESH_ADD_QUADRATIC_QUADRANGLE_TITLE - Add Quadratic Quadrangle - - - SMESH_ADD_QUADRATIC_TETRAHEDRON_TITLE - Add Quadratic Tetrahedron - - - SMESH_ADD_QUADRATIC_TRIANGLE_TITLE - Add Quadratic Triangle - - - SMESH_ADD_SUBMESH - SubMesh Construction - - - SMESH_ADD_TETRAS - Add Tetrahedron - - - SMESH_ADD_TETRAS_TITLE - Add Tetrahedron - - - SMESH_ADD_TO_GROUP - Add to group - - - SMESH_ADD_TRIANGLE - Add Triangle - - - SMESH_ADD_TRIANGLE_TITLE - Add Triangle - - - SMESH_ANGLE - Angle - - - SMESH_ARGUMENTS - Arguments - - - SMESH_AUTO_GROUPS - Automatically create groups - - - SMESH_AVAILABLE - Available - - - SMESH_AVAILABLE_ALGORITHMS - Available algorithms - - - SMESH_AVAILABLE_HYPOTHESES - Available hypotheses - - - SMESH_AXIS - Axis - - - SMESH_BAD_SELECTION - No valid selection - - - SMESH_BAD_MESH_SELECTION - No valid mesh selection - - - SMESH_BOUNDARYEDGES - Boundary Edges - - - SMESH_BUILD_COMPOUND_TITLE - Create a Compound - - - SMESH_BUT_ADD - A&dd - - - SMESH_BUT_APPLY - &Apply - - - SMESH_BUT_CANCEL - &Cancel - - - SMESH_BUT_CLOSE - &Close - - - SMESH_BUT_CREATE - Create - - - SMESH_BUT_DELETE - Delete - - - SMESH_BUT_FILTER - Set &Filters - - - SMESH_BUT_HELP - &Help - - - SMESH_BUT_NEW - New - - - SMESH_BUT_NO - &No - - - SMESH_BUT_OK - &Ok - - - SMESH_BUT_OVERWRITE - Over&write - - - SMESH_BUT_APPLY_AND_CLOSE - A&pply and Close - - - SMESH_BUT_REMOVE - &Remove - - - SMESH_BUT_SORT - &Sort List - - - SMESH_BUT_YES - &Yes - - - SMESH_CANT_ADD_HYP - Can not assign "%1": - - - - SMESH_CANT_RM_HYP - Can not unassign "%1": - - - - SMESH_CHECK_COLOR - Color - - - SMESH_CLIPPING_FROM - From <--- - - - SMESH_CLIPPING_INTO - ---> Into - - - SMESH_CLIPPING_TITLE - Change Clipping - - - SMESH_COMPUTE_SUCCEED - Mesh computation succeed - - - SMESH_EVALUATE_SUCCEED - Mesh evaluation succeed - - - SMESH_CONTENT - Content - - - SMESH_CONTINUE_MESH_VISUALIZATION - It seems that there is not enough memory to show the mesh -so that the application may crash. Do you wish to continue visualization? - - - SMESH_COORDINATES - Coordinates - - - SMESH_COPY_ELEMENTS - Copy Elements - - - SMESH_COPY_GROUPS - Copy groups - - - SMESH_CREATE_ALGORITHMS - Create algorithms - - - SMESH_CREATE_COPY - Create a copy - - - SMESH_CREATE_GROUP_TITLE - Create Group - - - SMESH_CREATE_GEO_GROUP - Create Groups from Geometry - - - SMESH_CREATE_HYPOTHESES - Create hypotheses - - - SMESH_CREATE_MESH - Create a new mesh - - - SMESH_CREATE_POLYHEDRAL_VOLUME_TITLE - Create polyhedral volume - - - SMESH_DIAGONAL - Diagonal Inversion - - - SMESH_DIAGONAL_INVERSION_TITLE - Diagonal Inversion - - - SMESH_DISTANCE - Distance - - - SMESH_DRS_1 - MED file contains no mesh with the given name - - - SMESH_DRS_2 - MED file has overlapped ranges of element numbers, the numbers from the file are ignored - - - SMESH_DRS_3 - Some elements were skipped due to incorrect file data - - - SMESH_DRS_4 - The file is incorrect, some data is missed - - - SMESH_DRS_EMPTY - The file is empty, there is nothing to be published - - - SMESH_DX - dX - - - SMESH_DY - dY - - - SMESH_DZ - dZ - - - SMESH_ELEM0D - 0D Element - - - SMESH_EDGE - Edge - - - SMESH_EDGES_CONNECTIVITY_TITLE - Edges Connectivity - - - SMESH_EDIT_GROUP_TITLE - Edit Group - - - SMESH_EDIT_GEOMGROUP_AS_GROUP_TITLE - Edit Group as Standalone - - - SMESH_EDIT_HYPOTHESES - Hypotheses Assignation - - - SMESH_EDIT_USED - Used - - - SMESH_ELEMENTS - Elements - - - SMESH_ELEMENTS_COLOR - Mesh Element Color - - - SMESH_ELEMENTS_TYPE - Elements Type - - - SMESH_ELEMENT_TYPE - Element Type - - - SMESH_ERROR - Error - - - SMESH_ERR_SCALARBAR_PARAMS - Warning! The parameters is incorrect - - - SMESH_EXPORT_FAILED - Mesh export failed. -Probably, there is not enough space on disk. - - - SMESH_EXPORT_MED_DUPLICATED_GRP - There are duplicated group names in mesh "%1". -You can cancel exporting and rename them, -otherwise some group names in the resulting MED file -will not match ones in the study. -Do you want to continue ? - - - SMESH_EXPORT_MED_DUPLICATED_MESH_NAMES - There are some meshes with the same names in the selection. -The result file may be incorrect. -Do you want to continue ? - - - SMESH_EXPORT_MED_V2_1 - During export mesh with name - "%1" to MED 2.1 -polygons and polyhedrons elements will be missed -For correct export use MED 2.2 -Are you sure want to export to MED 2.1 ? - - - SMESH_EXPORT_MED_VERSION_COLLISION - MED version of the file "%1" -is unknown or doesn't match the selected version. -Overwrite the file? - - - SMESH_EXPORT_MED_MESH_NAMES_COLLISION - The selected file already contains -meshes with the following names: %1 -The result file may be incorrect. -Overwrite the file? - - - SMESH_EXPORT_STL1 - Mesh - "%1" does not contain triangles - - - SMESH_EXPORT_STL2 - Mesh - "%1" contains another than triangles elements, they are ignored during writing to STL - - - SMESH_EXPORT_UNV - During export mesh with name - "%1" to UNV - pyramid's elements will be missed - - - SMESH_EXTRUSION - Extrusion - - - SMESH_EXTRUSION_TO_DISTANCE - Extrusion To Distance - - - SMESH_EXTRUSION_ALONG_VECTOR - Extrusion Along Vector - - - SMESH_FACE - Face - - - SMESH_FEATUREANGLE - Feature Angle - - - SMESH_FEATUREEDGES - Feature Edges - - - SMESH_FILE_EXISTS - The file "%1" already exists. -Do you want to overwrite it or -add the exported data to its contents? - - - SMESH_FONT_ARIAL - Arial - - - SMESH_FONT_BOLD - Bold - - - SMESH_FONT_COURIER - Courier - - - SMESH_FONT_ITALIC - Italic - - - SMESH_FONT_SCALARBAR - Font - - - SMESH_FONT_SHADOW - Shadow - - - SMESH_FONT_TIMES - Times - - - SMESH_GEOM_GROUP - Geometry group - - - SMESH_GROUP - Group - - - SMESH_GROUP_GEOMETRY - Group on geometry - - - SMESH_GROUP_SELECTED - %1 Groups - - - SMESH_GROUP_STANDALONE - Standalone group - - - SMESH_GROUP_TYPE - Group type - - - SMESH_HEIGHT - Height: - - - SMESH_HEXAS - Hexahedron - - - SMESH_HILIGHT_COLOR - Highlight Color - - - SMESH_HORIZONTAL - Horizontal - - - SMESH_HYPOTHESES - Hypotheses - - - SMESH_HYP_1 - Algorithm misses a hypothesis - - - SMESH_HYP_10 - Hypothesis and submesh dimensions mismatch - - - SMESH_HYP_11 - Shape is neither the main one, nor its subshape, nor a valid group - - - SMESH_HYP_12 - Geometry mismatches algorithm's expectation\nCheck algorithm documentation for supported geometry - - - SMESH_HYP_13 - Algorithm can't work without shape - - - SMESH_HYP_2 - There are concurrent hypotheses on a shape - - - SMESH_HYP_3 - Hypothesis has a bad parameter value - - - SMESH_HYP_4 - Submesh is ignored as there is another algorithm of upper dimension generating %1D elements - - - SMESH_HYP_5 - Algorithm hides algorithm(s) of lower dimension by generating all-dimensions elements - - - SMESH_HYP_6 - Unknown fatal error at hypothesis definition - - - SMESH_HYP_7 - Hypothesis is not suitable in the current context - - - SMESH_HYP_8 - Non-conform mesh is produced using applied hypotheses - - - SMESH_HYP_9 - Such dimention hypothesis is already assigned to the shape - - - SMESH_ID_DIAGONAL - Id Edges - - - SMESH_ID_ELEMENTS - Id Elements - - - SMESH_ID_FACES - Id Faces - - - SMESH_ID_NODES - Id Nodes - - - SMESH_INCORRECT_INPUT - Incorrect input data! - - - SMESH_INFORMATION - Information - - - SMESH_INIT - Mesh - - - SMESH_INIT_MESH - Mesh Construction - - - SMESH_INSUFFICIENT_DATA - Insufficient input value - - - SMESH_LABELS - Labels: - - - SMESH_LABELS_COLORS_SCALARBAR - Colors && Labels - - - SMESH_LENGTH - Length - - - SMESH_MAKE_GROUPS - Generate groups - - - SMESH_MANIFOLDEDGES - Manifold Edges - - - SMESH_MAX - Max - - - SMESH_MEN_ALGORITHMS - Algorithms - - - SMESH_MEN_APPLIED_ALGORIHTMS - Applied Algorithms - - - SMESH_MEN_APPLIED_HYPOTHESIS - Applied Hypotheses - - - SMESH_MEN_COMPONENT - SMESH - - - SMESH_MEN_HYPOTHESIS - Hypotheses - - - SMESH_MEN_SubMeshesOnCompound - SubMeshes On Compound - - - SMESH_MEN_SubMeshesOnEdge - SubMeshes On Edge - - - SMESH_MEN_SubMeshesOnFace - SubMeshes On Face - - - SMESH_MEN_SubMeshesOnSolid - SubMeshes On Solid - - - SMESH_MEN_SubMeshesOnVertex - SubMeshes On Vertex - - - SMESH_AUTOMATIC - Automatic - - - SMESH_MANUAL - Manual - - - SMESH_MERGE_ELEMENTS - Merge elements - - - SMESH_MODE - Mode - - - SMESH_MERGED_ELEMENTS - %1 elements successfully merged. - - - SMESH_MERGED_NODES - %1 nodes successfully merged. - - - SMESH_NO_ELEMENTS_DETECTED - There are no elements to merge. - - - SMESH_NO_NODES_DETECTED - There are no nodes to merge. - - - SMESH_MERGE_NODES - Merge nodes - - - SMESH_MESH - Mesh - - - SMESH_MESHINFO_0DELEMS - 0D Elements - - - SMESH_MESHINFO_ALL_TYPES - Heterogenous - - - SMESH_MESHINFO_EDGES - Edges - - - SMESH_MESHINFO_ELEMENTS - Elements - - - SMESH_MESHINFO_ENTITIES - Entities - - - SMESH_MESHINFO_FACES - Faces - - - SMESH_MESHINFO_HEXAS - Hexahedrons - - - SMESH_MESHINFO_NAME - Name - - - SMESH_MESHINFO_NODES - Nodes - - - SMESH_MESHINFO_ORDER0 - Total - - - SMESH_MESHINFO_ORDER1 - Linear - - - SMESH_MESHINFO_ORDER2 - Quadratic - - - SMESH_MESHINFO_POLYEDRES - Polyhedrons - - - SMESH_MESHINFO_POLYGONES - Polygons - - - SMESH_MESHINFO_PRISMS - Prisms - - - SMESH_MESHINFO_PYRAS - Pyramids - - - SMESH_MESHINFO_QUADRANGLES - Quadrangles - - - SMESH_MESHINFO_TETRAS - Tetrahedrons - - - SMESH_MESHINFO_TITLE - Mesh Infos - - - SMESH_MESHINFO_TOTAL - Total - - - SMESH_MESHINFO_TRIANGLES - Triangles - - - SMESH_MESHINFO_TYPE - Type - - - SMESH_MESHINFO_VOLUMES - Volumes - - - SMESH_MIN - Min - - - SMESH_MOVE - Move - - - SMESH_MOVE_ELEMENTS - Move Elements - - - SMESH_MOVE_NODES_TITLE - Move Node - - - SMESH_NAME - Name - - - SMESH_NODES - Nodes - - - SMESH_NONMANIFOLDEDGES - Non Manifold Edges - - - SMESH_NORMAL - Normal - - - SMESH_NO_MESH_VISUALIZATION - There is not enough memory to show the mesh - - - SMESH_NUMBEROFCOLORS - Nb of colors: - - - SMESH_NUMBEROFLABELS - Nb of labels: - - - SMESH_NUMBEROFSTEPS - Number of steps: - - - SMESH_OBJECTS_SELECTED - %1_objects - - - SMESH_OBJECT_ALGORITHM - Algorithm - - - SMESH_OBJECT_GEOM - Geometrical Object - - - SMESH_OBJECT_HYPOTHESIS - Hypothesis - - - SMESH_OBJECT_MESH - Mesh - - - SMESH_OBJECT_MESHorSUBMESH - Mesh or SubMesh - - - SMESH_OPERATION_FAILED - Operation failed - - - SMESH_ORIENTATION - Orientation - - - SMESH_ORIENTATION_ELEMENTS_TITLE - Change Orientation - - - SMESH_OUTLINE_COLOR - Mesh Object Color - - - SMESH_PARAMETERS - Parameters - - - SMESH_PLANE - Plane - - - SMESH_POINT - Point - - - SMESH_POINT_1 - Point 1 - - - SMESH_POINT_2 - Point 2 - - - SMESH_BASE_POINT - Base Point - - - SMESH_POLYEDRE_CREATE_ERROR - Polyedron creation error - - - SMESH_POLYEDRON - Polyhedron - - - SMESH_POLYGON - Polygon - - - SMESH_POSITION_SIZE_SCALARBAR - Origin && Size - - - SMESH_PRECISION - Precision - - - SMESH_PREFERENCES_SCALARBAR - Scalar Bar Preferences - - - SMESH_PREF_SELECTION - Preferences - Selection - - - SMESH_PRESELECTION - Preselection - - - SMESH_PRISM - Prism - - - SMESH_PROPERTIES_SCALARBAR - Scalar Bar Properties - - - SMESH_PYRAMID - Pyramid - - - SMESH_QUADRANGLE - Quadrangle - - - SMESH_QUADRATIC_EDGE - Quadratic Edge - - - SMESH_QUADRATIC_HEXAHEDRON - Quadratic Hexahedron - - - SMESH_QUADRATIC_PENTAHEDRON - Quadratic Pentahedron - - - SMESH_QUADRATIC_PYRAMID - Quadratic Pyramid - - - SMESH_QUADRATIC_QUADRANGLE - Quadratic Quadrangle - - - SMESH_QUADRATIC_TETRAHEDRON - Quadratic Tetrahedron - - - SMESH_QUADRATIC_TRIANGLE - Quadratic Triangle - - - SMESH_RANGE_MAX - Max value: - - - SMESH_RANGE_MIN - Min value: - - - SMESH_RANGE_SCALARBAR - Scalar Range - - - SMESH_REALLY_DELETE - Do you really want to delete this %1 object(s)? : %2 - - - SMESH_REMOVE - Remove - - - SMESH_REMOVE_ELEMENTS_TITLE - Remove Elements - - - SMESH_REMOVE_NODES_TITLE - Remove Nodes - - - SMESH_RENUMBERING - Renumbering - - - SMESH_RENUMBERING_ELEMENTS_TITLE - Renumbering elements - - - SMESH_RENUMBERING_NODES_TITLE - Renumbering nodes - - - SMESH_REVERSE - Reverse - - - SMESH_REVOLUTION - Revolution - - - SMESH_RM_HYP_WRN - "%1" unassigned but: - - - - SMESH_ROTATION - Rotation - - - SMESH_ROTATION_TITLE - Rotation about an axis - - - SMESH_SCALARBAR - Scalar Bar - - - SMESH_SEGMENTS - Segments - - - SMESH_SELECTION - Selection - - - SMESH_SELECT_FROM - Select From - - - SMESH_SELECT_WHOLE_MESH - Select whole mesh, submesh or group - - - SMESH_SET_COLOR - Color group - - - SMESH_SEWING - Sewing - - - SMESH_SMOOTHING - Smoothing - - - SMESH_STANDARD_MESHINFO_TITLE - Standard Mesh Infos - - - SMESH_SUBMESH - SubMesh - - - SMESH_SUBMESH_SELECTED - %1 SubMeshes - - - SMESH_SYMMETRY - Symmetry - - - SMESH_TETRAS - Tetrahedron - - - SMESH_TITLE - Title: - - - SMESH_TOLERANCE - Tolerance - - - SMESH_TRANSLATION - Translation - - - SMESH_SCALE_TITLE - Scale Transform - - - SMESH_SCALE - Scale - - - SMESH_SCALE_FACTOR - Scale Factor : - - - SMESH_SCALE_FACTOR_X - Scale Factor X : - - - SMESH_SCALE_FACTOR_Y - Scale Factor Y : - - - SMESH_SCALE_FACTOR_Z - Scale Factor Z : - - - SMESH_TRANSPARENCY_OPAQUE - ---> Opaque - - - SMESH_TRANSPARENCY_TITLE - Change Transparency - - - SMESH_TRANSPARENCY_TRANSPARENT - Transparent <--- - - - SMESH_TRIANGLE - Triangle - - - SMESH_UPDATEVIEW - Update View - - - SMESH_VALUE - Value - - - SMESH_VECTOR - Vector - - - SMESH_VERTICAL - Vertical - - - SMESH_VISU_PROBLEM - Mesh visualization failed, probably due to lack of memory - - - SMESH_VISU_PROBLEM_CLEAR - Mesh visualization failed, no memory even to show a message, -so all visual data have been removed to let the application live. -Consider saving your work before application crash - - - SMESH_VOLUME - Volume - - - SMESH_WARNING - Warning - - - SMESH_WHAT_IS_TITLE - Mesh Element Info - - - SMESH_WIDTH - Width: - - - SMESH_WRN_ALGORITHM_ALREADYEXIST - Algorithm already exists - - - SMESH_WRN_COMPUTE_FAILED - Mesh computation failed - - - SMESH_WRN_EVALUATE_FAILED - Mesh evaluation failed - - - SMESH_WRN_EMPTY_NAME - Empty name is not valid - - - SMESH_WRN_HYPOTHESIS_ALREADYEXIST - Hypothesis already exists - - - SMESH_WRN_HYPOTHESIS_NOTEXIST - Hypothesis or Algorithm not exists - - - SMESH_WRN_MISSING_PARAMETERS - Missing parameters - - - SMESH_WRN_NO_AVAILABLE_DATA - No available data in selection - - - SMESH_WRN_SELECTIONMODE_DIAGONAL - Activate Link Selection Mode - - - SMESH_WRN_SELECTIONMODE_ELEMENTS - Activate Elements Selection Mode - - - SMESH_WRN_SELECTIONMODE_NODES - Activate Nodes Selection Mode - - - SMESH_WRN_VIEWER_VTK - Study frame with VTK Viewer must be activated - - - SMESH_WRN_WARNING - Warning - - - SMESH_X - X - - - SMESH_X_SCALARBAR - X: - - - SMESH_Y - Y - - - SMESH_Y_SCALARBAR - Y: - - - SMESH_Z - Z - - - STATE_ALGO_MISSING - %3 %2D algorithm is missing - - - STATE_HYP_BAD_GEOMETRY - %3 %2D algorithm "%1" is assigned to geometry mismatching its expectation - - - STATE_HYP_BAD_PARAMETER - Hypothesis of %3 %2D algorithm "%1" has a bad parameter value - - - STATE_HYP_MISSING - %3 %2D algorithm "%1" misses %4D hypothesis - - - STATE_HYP_NOTCONFORM - %3 %2D algorithm "%1" would produce not conform mesh: global "Not Conform Mesh Allowed" hypotesis is missing - - - STB_ADV_INFO - Advanced Mesh Infos - - - STB_ALL - All - - - STB_AREA - Area - - - STB_ASPECT - Aspect Ratio - - - STB_ASPECT_3D - Aspect Ratio 3D - - - STB_AUTO_COLOR - Auto color - - - STB_AUTO_UPD - Automatic update - - - STB_BUILD_COMPOUND - Build Compound Mesh - - - STB_CLIP - Clipping - - - STB_COLORS - Colors / Size - - - STB_COMPUTE - Compute - - - STB_PRECOMPUTE - Preview - - - STB_EVALUATE - Evaluate - - - STB_CONNECTION - Borders at Multi-Connection - - - STB_CONNECTION_2D - Borders at Multi-Connection 2D - - - STB_CONSTRUCT_GROUP - Construct Group - - - STB_CONV_TO_QUAD - Convert to/from quadratic - - - STB_2D_FROM_3D - Create 2D mesh from 3D - - - STB_MESH_ORDER - Change submesh priority - - - STB_CREATE_GROUP - Create Group - - - STB_CREATE_GEO_GROUP - Create Groups from Geometry - - - STB_CREATE_MESH - Create Mesh - - - STB_CREATE_SUBMESH - Create Sub-mesh - - - STB_CUT - Cutting of quadrangles - - - STB_CUT_GROUP - Cut Groups - - - STB_DAT - Import DAT file - - - STB_DELETE - Delete - - - STB_DEL_GROUP - Delete Groups - - - STB_FACE_ORIENTATION - Orientation of faces - - - STB_DISABLE_AUTO_COLOR - Disable auto color - - - STB_DISPLAY_ONLY - Show only - - - STB_DISP_ENT - Display entity - - - STB_ELEM0D - 0D Element - - - STB_ELEMS0D - 0D Elements - - - STB_EDGE - Edge - - - STB_EDGES - Edges - - - STB_EDIT_GROUP - Edit Group - - - STB_EDIT_GEOMGROUP_AS_GROUP - Edit Group as Standalone - - - STB_EDIT_HYPO - Edit Hypothesis - - - STB_EDIT_MESHSUBMESH - Edit Mesh/Sub-mesh - - - STB_EXPORT_DAT - Export to DAT file - - - STB_EXPORT_MED - Export to MED file - - - STB_EXPORT_SAUV - Export to SAUV (ASCII) file - - - STB_EXPORT_STL - Export to STL file - - - STB_EXPORT_UNV - Export to UNV file - - - STB_EXTRUSION - Extrusion - - - STB_EXTRUSION_ALONG - Extrusion along a path - - - STB_FACES - Faces - - - STB_FREE_BORDER - Free Borders - - - STB_FREE_EDGE - Free Edges - - - STB_FREE_NODE - Free Nodes - - - - - STB_FREE_FACES - Free Faces - - - STB_GLOBAL_HYPO - Global Hypothesis - - - STB_HEXA - Hexahedron - - - STB_HIDE - Hide - - - STB_INT_GROUP - Intersect Groups - - - STB_INV - Diagonal Inversion - - - STB_LENGTH - Length - - - STB_LENGTH_2D - Length 2D - - - STB_MAP - Pattern mapping - - - STB_MED - Import MED file - - - STB_SAUV - Import SAUV (ASCII) file - - - STB_MERGE - Merge nodes - - - STB_MERGE_ELEMENTS - Merge elements - - - STB_MESH_THROU_POINT - Mesh to pass through a point - - - STB_MIN_ANG - Minimum Angle - - - STB_MOVE - Move Node - - - STB_NODE - Node - - - STB_NODES - Nodes - - - STB_NUM_ELEMENTS - Display Elements - - - STB_NUM_NODES - Display Nodes - - - STB_ORIENT - Orientation - - - STB_POLYGON - Polygon - - - STB_POLYHEDRON - Polyhedron - - - STB_PRECISION - Precision - - - STB_QUAD - Quadrangle - - - STB_QUADRATIC_EDGE - Quadratic Edge - - - STB_QUADRATIC_HEXAHEDRON - Quadratic Hexahedron - - - STB_QUADRATIC_PENTAHEDRON - Quadratic Pentahedron - - - STB_QUADRATIC_PYRAMID - Quadratic Pyramid - - - STB_QUADRATIC_QUADRANGLE - Quadratic Quadrangle - - - STB_QUADRATIC_TETRAHEDRON - Quadratic Tetrahedron - - - STB_QUADRATIC_TRIANGLE - Quadratic Triangle - - - STB_REMOVE_ELEMENTS - Remove elements - - - STB_REMOVE_NODES - Remove nodes - - - STB_RENAME - Rename - - - STB_RENUM_ELEMENTS - Renumbering elements - - - STB_RENUM_NODES - Renumbering nodes - - - STB_RESET - Reset - - - STB_REVOLUTION - Revolution - - - STB_ROT - Rotation - - - STB_SCALAR_BAR - Scalar bar - - - STB_SCALAR_BAR_PROP - Scalar bar Properties - - - STB_SELECTION - Selection - - - STB_SEL_FILTER_LIB - Selection filters library - - - STB_SEW - Sewing - - - STB_SHADE - Shading - - - STB_SHOW - Show - - - STB_SHRINK - Shrink - - - STB_SKEW - Skew - - - STB_SMOOTH - Smoothing - - - STB_STD_INFO - Standard Mesh Infos - - - STB_SYM - Symmetry - - - STB_TAPER - Taper - - - STB_TETRA - Tetrahedron - - - STB_TRANS - Translation - - - STB_SCALE - Scale Transform - - - STB_TRANSP - Transparency - - - STB_TRIANGLE - Triangle - - - STB_UNASSIGN - Unassign - - - STB_UNION - Union of triangles - - - STB_UNION2 - Union of two triangles - - - STB_UNV - Import UNV file - - - STB_UN_GROUP - Union Groups - - - STB_UNDERLYING_ELEMS - Create groups of entities from existing groups of superior dimensions - - - STB_UPDATE - Update - - - STB_VOLUMES - Volumes - - - STB_VOLUME_3D - Volume - - - STB_WARP - Warping angle - - - STB_WHAT_IS - Mesh Element Info - - - STB_WIRE - Wireframe - - - TAPER_ELEMENTS - Taper - - - TB_ADD_REMOVE - Add/Remove Toolbar - - - TB_CTRL - Controls Toolbar - - - TB_DISP_MODE - Display Mode Toolbar - - - TB_HYPO - Hypotheses Toolbar - - - TB_MESH - Mesh Toolbar - - - TB_MODIFY - Modification Toolbar - - - TOP_ADV_INFO - Advanced Mesh Infos - - - TOP_ALL - All - - - TOP_AREA - Area - - - TOP_ASPECT - Aspect Ratio - - - TOP_ASPECT_3D - Aspect Ratio 3D - - - TOP_AUTO_COLOR - Auto color - - - TOP_AUTO_UPD - Automatic update - - - TOP_BUILD_COMPOUND - Build Compound Mesh - - - TOP_CLIP - Clipping - - - TOP_COLORS - Colors / Size - - - TOP_COMPUTE - Compute - - - TOP_PRECOMPUTE - Preview - - - TOP_EVALUATE - Evaluate - - - TOP_CONNECTION - Borders at Multi-Connection - - - TOP_CONNECTION_2D - Borders at Multi-Connection 2D - - - TOP_CONSTRUCT_GROUP - Construct Group - - - TOP_CONV_TO_QUAD - Convert to/from quadratic - - - TOP_2D_FROM_3D - Create 2D mesh from 3D - - - TOP_MESH_ORDER - Change submesh priority - - - TOP_CREATE_GROUP - Create Group - - - TOP_CREATE_GEO_GROUP - Create Groups from Geometry - - - TOP_CREATE_MESH - Create Mesh - - - TOP_CREATE_SUBMESH - Create Sub-mesh - - - TOP_CUT - Cutting of quadrangles - - - TOP_CUT_GROUP - Cut Groups - - - TOP_DAT - Import DAT file - - - TOP_DELETE - Delete - - - TOP_DEL_GROUP - Delete Groups - - - TOP_FACE_ORIENTATION - Orientation of faces - - - TOP_DISABLE_AUTO_COLOR - Disable auto color - - - TOP_DISPLAY_ONLY - Show only - - - TOP_DISP_ENT - Display entity - - - TOP_ELEM0D - 0D Element - - - TOP_ELEMS0D - 0D Elements - - - TOP_EDGE - Edge - - - TOP_EDGES - Edges - - - TOP_EDIT_GROUP - Edit Group - - - TOP_EDIT_GEOMGROUP_AS_GROUP - Edit Group as Standalone - - - TOP_EDIT_HYPO - Edit Hypothesis - - - TOP_EDIT_MESHSUBMESH - Edit Mesh/Sub-mesh - - - TOP_EXPORT_DAT - Export to DAT file - - - TOP_EXPORT_MED - Export to MED file - - - TOP_EXPORT_SAUV - Export to SAUV (ASCII) file - - - TOP_EXPORT_STL - Export to STL file - - - TOP_EXPORT_UNV - Export to UNV file - - - TOP_EXTRUSION - Extrusion - - - TOP_EXTRUSION_ALONG - Extrusion along a path - - - TOP_FACES - Faces - - - TOP_FREE_BORDER - Free Borders - - - TOP_FREE_EDGE - Free Edges - - - TOP_FREE_NODE - Free Nodes - - - - - TOP_FREE_FACES - Free Faces - - - TOP_GLOBAL_HYPO - Global Hypothesis - - - TOP_HEXA - Hexahedron - - - TOP_HIDE - Hide - - - TOP_INT_GROUP - Intersect Groups - - - TOP_INV - Diagonal Inversion - - - TOP_LENGTH - Length - - - TOP_LENGTH_2D - Length 2D - - - TOP_MAP - Pattern mapping - - - TOP_MED - Import MED file - - - TOP_SAUV - Import SAUV (ASCII) file - - - TOP_MERGE - Merge nodes - - - TOP_MERGE_ELEMENTS - Merge elements - - - TOP_MESH_THROU_POINT - Mesh to pass through a point - - - TOP_MIN_ANG - Minimum Angle - - - TOP_MOVE - Move Node - - - TOP_NODE - Node - - - TOP_NODES - Nodes - - - TOP_NUM_ELEMENTS - Display Elements - - - TOP_NUM_NODES - Display Nodes - - - TOP_ORIENT - Orientation - - - TOP_POLYGON - Polygon - - - TOP_POLYHEDRON - Polyhedron - - - TOP_PRECISION - Precision - - - TOP_QUAD - Quadrangle - - - TOP_QUADRATIC_EDGE - Quadratic Edge - - - TOP_QUADRATIC_HEXAHEDRON - Quadratic Hexahedron - - - TOP_QUADRATIC_PENTAHEDRON - Quadratic Pentahedron - - - TOP_QUADRATIC_PYRAMID - Quadratic Pyramid - - - TOP_QUADRATIC_QUADRANGLE - Quadratic Quadrangle - - - TOP_QUADRATIC_TETRAHEDRON - Quadratic Tetrahedron - - - TOP_QUADRATIC_TRIANGLE - Quadratic Triangle - - - TOP_REMOVE_ELEMENTS - Remove elements - - - TOP_REMOVE_NODES - Remove nodes - - - TOP_RENAME - Rename - - - TOP_RENUM_ELEMENTS - Renumbering elements - - - TOP_RENUM_NODES - Renumbering nodes - - - TOP_RESET - Reset - - - TOP_REVOLUTION - Revolution - - - TOP_ROT - Rotation - - - TOP_SCALAR_BAR - Scalar bar - - - TOP_SCALAR_BAR_PROP - Scalar bar Properties - - - TOP_SELECTION - Selection - - - TOP_SEL_FILTER_LIB - Selection filters library - - - TOP_SEW - Sewing - - - TOP_SHADE - Shading - - - TOP_SHOW - Show - - - TOP_SHRINK - Shrink - - - TOP_SKEW - Skew - - - TOP_SMOOTH - Smoothing - - - TOP_STD_INFO - Standard Mesh Infos - - - TOP_SYM - Symmetry - - - TOP_TAPER - Taper - - - TOP_TETRA - Tetrahedron - - - TOP_TRANS - Translation - - - TOP_SCALE - Scale Transform - - - TOP_TRANSP - Transparency - - - TOP_TRIANGLE - Triangle - - - TOP_UNASSIGN - Unassign - - - TOP_UNION - Union of triangles - - - TOP_UNION2 - Union of two triangles - - - TOP_UNV - Import UNV file - - - TOP_UN_GROUP - Union Groups - - - TOP_UNDERLYING_ELEMS - Create groups of entities from existing groups of superior dimensions - - - TOP_UPDATE - Update - - - TOP_VOLUMES - Volumes - - - TOP_VOLUME_3D - Volume - - - TOP_WARP - Warping angle - - - TOP_WHAT_IS - Mesh Element Info - - - TOP_WIRE - Wireframe - - - VOLUME_3D_ELEMENTS - Area - - - WARP_ELEMENTS - Warping - - - MEN_FILE_INFO - MED File Information - - - SMESH_WRN_NO_APPROPRIATE_SELECTION - No appropriate objects selected - - - MEN_CLEAR_MESH - Clear Mesh Data - - - TOP_CLEAR_MESH - Clear Mesh Data - - - STB_CLEAR_MESH - Clear Mesh Data - - - SMESH_IMPORT_MESH - Import mesh data from files - - - SMESH_ERR_NOT_SUPPORTED_FORMAT - Unsupported file format - - - SMESH_ERR_UNKNOWN_IMPORT_ERROR - Unknown error - - - SMESH_IMPORT_ERRORS - Import operation has finished with errors: - - - SMESH_DRS_SOME_EMPTY - One or more mesh files were empty, data has not been published - - - NO_MESH_SELECTED - No mesh selected - - - SMESH_PREF_def_precision - Default precision - - - SMESH_PREF_length_precision - Length precision - - - SMESH_PREF_angle_precision - Angular precision - - - SMESH_PREF_len_tol_precision - Length tolerance precision - - - SMESH_PREF_parametric_precision - Parametric precision - - - SMESH_PREF_area_precision - Area precision - + + + @default + + SMESH_EXPORT_MESH + Export mesh + + + MED_FILES_FILTER + MED files + + + IDEAS_FILES_FILTER + IDEAS files + + + DAT_FILES_FILTER + DAT files + + + TEXT_FILES_FILTER + TXT files + + + MED_VX_FILES_FILTER + MED %1 files + + + STL_ASCII_FILES_FILTER + STL ASCII files + + + STL_BIN_FILES_FILTER + STL binary files + + + ALL_FILES_FILTER + All files + + + AREA_ELEMENTS + Area + + + ASPECTRATIO_3D_ELEMENTS + Aspect Ratio 3D + + + ASPECTRATIO_ELEMENTS + Aspect Ratio + + + COL_ALGO_HEADER + Algorithm + + + COL_ERROR_HEADER + Error + + + COL_SHAPE_HEADER + SubShape + + + COMPERR_ALGO_FAILED + Algorithm failed + + + COMPERR_BAD_INPUT_MESH + Invalid input mesh + + + COMPERR_BAD_SHAPE + Unexpected geometry + + + COMPERR_EXCEPTION + Unknown exception + + + COMPERR_MEMORY_PB + Memory allocation problem + + + COMPERR_OCC_EXCEPTION + OCC exception + + + COMPERR_OK + No errors + + + COMPERR_SLM_EXCEPTION + SALOME exception + + + COMPERR_STD_EXCEPTION + std::exception + + + SMESH_GEOM + Geometry + + + DIRECT_GEOM_SELECTION + Direct geometry selection + + + ELEMENT_ID + Element ID + + + FREE_BORDERS + Free Borders + + + GEOMETRY_NAME + Geometry name + + + GEOM_BY_MESH_ELEM_SELECTION + Find geometry by mesh element selection + + + GLOBAL_ALGO + Global + + + INF_SELECT_OBJECT + Select an object + + + LENGTH2D_EDGES + Length 2D + + + LENGTH_EDGES + Length + + + LOCAL_ALGO + Local + + + MAX_ELEMENT_LENGTH_2D + Element Diameter 2D + + + MAX_ELEMENT_LENGTH_3D + Element Diameter 3D + + + MEN_ADD + Add + + + MEN_ADV_INFO + Mesh Information + + + MEN_ALL + All + + + MEN_AREA + Area + + + MEN_ASPECT + Aspect Ratio + + + MEN_ASPECT_3D + Aspect Ratio 3D + + + MEN_AUTO_COLOR + Auto Color + + + MEN_AUTO_UPD + Automatic Update + + + MEN_BUILD_COMPOUND + Build Compound + + + MEN_CLIP + Clipping + + + MEN_COLORS + Colors / Size + + + MEN_COMPUTE + Compute + + + MEN_PRECOMPUTE + Preview + + + MEN_EVALUATE + Evaluate + + + MEN_CONNECTION + Borders at Multi-Connection + + + MEN_CONNECTION_2D + Borders at Multi-Connection 2D + + + MEN_CONSTRUCT_GROUP + Construct Group + + + MEN_CONV_TO_QUAD + Convert to/from quadratic + + + MEN_2D_FROM_3D + Create boundary elements + + + MEN_MESH_ORDER + Change submesh priority + + + MEN_CREATE_GROUP + Create Group + + + MEN_CREATE_GEO_GROUP + Create Groups from Geometry + + + MEN_CREATE_MESH + Create Mesh + + + MEN_CREATE_SUBMESH + Create Sub-mesh + + + MEN_CTRL + Controls + + + MEN_NODE_CTRL + Node Controls + + + MEN_EDGE_CTRL + Edge Controls + + + MEN_FACE_CTRL + Face Controls + + + MEN_VOLUME_CTRL + Volume Controls + + + MEN_CUT + Cutting of Quadrangles + + + MEN_CUT_GROUP + Cut Groups + + + MEN_DAT + DAT File + + + MEN_DELETE + Delete + + + MEN_DEL_GROUP + Delete Groups + + + MEN_FACE_ORIENTATION + Orientation of Faces + + + MEN_DISABLE_AUTO_COLOR + Disable Auto Color + + + MEN_DISPLAY_ONLY + Show Only + + + MEN_DISPMODE + Display Mode + + + MEN_DISP_ENT + Display Entity + + + MEN_ELEM0D + 0D Element + + + MEN_ELEMS0D + 0D Elements + + + MEN_EDGE + Edge + + + MEN_EDGES + Edges + + + MEN_EDIT + Edit + + + MEN_EDIT_GROUP + Edit Group + + + MEN_EDIT_GEOMGROUP_AS_GROUP + Edit Group as Standalone + + + MEN_EDIT_HYPO + Edit Hypothesis + + + MEN_EDIT_MESHSUBMESH + Edit Mesh/Sub-mesh + + + MEN_EXPORT + Export + + + MEN_EXPORT_DAT + Export to DAT File + + + MEN_EXPORT_MED + Export to MED File + + + MEN_EXPORT_SAUV + Export to SAUV (ASCII) file + + + MEN_EXPORT_STL + Export to STL File + + + MEN_EXPORT_UNV + Export to UNV File + + + MEN_EXTRUSION + Extrusion + + + MEN_EXTRUSION_ALONG + Extrusion Along a Path + + + MEN_FACES + Faces + + + MEN_FILE + File + + + MEN_FIND_ELEM + Find Element by Point + + + TOP_FIND_ELEM + Find Element by Point + + + STB_FIND_ELEM + Find Element by Point + + + MEN_FREE_BORDER + Free Borders + + + MEN_FREE_EDGE + Free Edges + + + MEN_FREE_NODE + Free Nodes + + + MEN_FREE_FACES + Free Faces + + + MEN_GLOBAL_HYPO + Global Hypothesis + + + MEN_HEXA + Hexahedron + + + MEN_HIDE + Hide + + + MEN_HYPO + Hypotheses + + + MEN_IMPORT + Import + + + MEN_INT_GROUP + Intersect Groups + + + MEN_INV + Diagonal Inversion + + + MEN_LENGTH + Length + + + MEN_LENGTH_2D + Length 2D + + + MEN_MAP + Pattern Mapping + + + MEN_MAX_ELEMENT_LENGTH_2D + Element Diameter 2D + + + MEN_MAX_ELEMENT_LENGTH_3D + Element Diameter 3D + + + MEN_MED + MED file + + + MEN_SAUV + SAUV (ASCII) file + + + MEN_MERGE + Merge Nodes + + + MEN_MERGE_ELEMENTS + Merge Elements + + + MEN_MESH + Mesh + + + MEN_MESH_THROU_POINT + Move Node + + + MEN_MIN_ANG + Minimum Angle + + + MEN_MODIFY + Modification + + + MEN_MEASURE + Measurements + + + MEN_MEASURE_MIN_DIST + Minimum Distance + + + STB_MEASURE_MIN_DIST + Calculate minimum distance between two objects + + + TOP_MEASURE_MIN_DIST + Minimum distance + + + MEN_MEASURE_BND_BOX + Bounding Box + + + STB_MEASURE_BND_BOX + Calculate bounding box for the selected object(s) + + + TOP_MEASURE_BND_BOX + Bounding box + + + MEN_MOVE + Move Node + + + MEN_NODE + Node + + + MEN_NODES + Nodes + + + MEN_NUM + Numbering + + + MEN_NUM_ELEMENTS + Display Elements # + + + MEN_NUM_NODES + Display Nodes # + + + MEN_ORIENT + Orientation + + + MEN_POLYGON + Polygon + + + MEN_POLYHEDRON + Polyhedron + + + MEN_PRECISION + Precision + + + MEN_PREF + Preferences + + + MEN_QUAD + Quadrangle + + + MEN_QUADRATIC_EDGE + Quadratic Edge + + + MEN_QUADRATIC_HEXAHEDRON + Quadratic Hexahedron + + + MEN_QUADRATIC_PENTAHEDRON + Quadratic Pentahedron + + + MEN_QUADRATIC_PYRAMID + Quadratic Pyramid + + + MEN_QUADRATIC_QUADRANGLE + Quadratic Quadrangle + + + MEN_QUADRATIC_TETRAHEDRON + Quadratic Tetrahedron + + + MEN_QUADRATIC_TRIANGLE + Quadratic Triangle + + + MEN_QUALITY + Quality Controls + + + MEN_REMOVE + Remove + + + MEN_REMOVE_ELEMENTS + Elements + + + MEN_REMOVE_NODES + Nodes + + + MEN_REMOVE_ORPHAN_NODES + Orphan Nodes + + + MEN_RENAME + Rename + + + MEN_RENUM + Renumbering + + + MEN_RENUM_ELEMENTS + Elements + + + MEN_RENUM_NODES + Nodes + + + MEN_RESET + Reset + + + MEN_SAVE_DISTRIBUTION + Export Distribution... + + + MEN_SHOW_DISTRIBUTION + Show Distribution + + + MEN_REVOLUTION + Revolution + + + MEN_ROT + Rotation + + + MEN_SCALAR_BAR + Scalar Bar + + + MEN_SCALAR_BAR_PROP + Scalar Bar Properties + + + MEN_SELECTION + Selection + + + MEN_SEL_FILTER_LIB + Selection Filters Library + + + MEN_SEW + Sewing + + + MEN_SHADE + Shading + + + MEN_QUADRATIC_REPRESENT + 2D Quadratic + + + MEN_LINE_REPRESENTATION + Lines + + + MEN_ARC_REPRESENTATION + Arcs + + + MEN_SHOW + Show + + + MEN_SHRINK + Shrink + + + MEN_SKEW + Skew + + + MEN_SMOOTH + Smoothing + + + MEN_STD_INFO + Standard Mesh Infos + + + MEN_STL + STL File + + + MEN_SYM + Symmetry + + + MEN_TAPER + Taper + + + MEN_TETRA + Tetrahedron + + + MEN_TOOLS + Tools + + + MEN_TRANS + Translation + + + MEN_SCALE + Scale Transform + + + MEN_DUPLICATE_NODES + Duplicate Nodes + + + MEN_TRANSF + Transformation + + + MEN_TRANSP + Transparency + + + MEN_TRIANGLE + Triangle + + + MEN_UNASSIGN + Unassign + + + MEN_UNION + Union of Triangles + + + MEN_UNION2 + Union of Two Triangles + + + MEN_UNV + UNV File + + + MEN_UN_GROUP + Union Groups + + + MEN_UNDERLYING_ELEMS + Group of underlying entities + + + MEN_UPDATE + Update + + + MEN_VIEW + View + + + MEN_VOLUMES + Volumes + + + MEN_VOLUME_3D + Volume + + + MEN_WARP + Warping Angle + + + MEN_WHAT_IS + Mesh Element Information + + + MEN_WIRE + Wireframe + + + MEN_SPLIT_TO_TETRA + Split into Tetrahedra + + + TOP_SPLIT_TO_TETRA + Split into Tetrahedra + + + STB_SPLIT_TO_TETRA + Split into Tetrahedra + + + MESHERS_FILE_CANT_OPEN + Can not open resource file + + + MESHERS_FILE_CHECK_VARIABLE + Check environment variable SMESH_MeshersList + + + MESHERS_FILE_NO_VARIABLE + Environment variable SMESH_MeshersList is not defined + + + MESH_IS_NOT_SELECTED + There is no selected mesh +Please, select a mesh and try again + + + MESH_NODE + Node + + + MESH_NODE_TITLE + Add Node + + + MINIMUMANGLE_ELEMENTS + Minimum Angle + + + MULTI2D_BORDERS + Borders at Multi-Connections 2D + + + MULTI_BORDERS + Borders at Multi-Connections + + + GROUP_NAME_IS_EMPTY + Name of group is not specified. +Please enter a name of new group to be created or choose an existing one. + + + MESH_STANDALONE_GRP_CHOSEN + Group on geometry is chosen: %1. +Do you want to convert it to the standalone group? + + + NODE_ID + Node ID + + + NON_SMESH_OBJECTS_SELECTED + There are objects selected which do not belong to %1 component. + + + PREVIEW + Preview + + + SKEW_ELEMENTS + Skew + + + SMESHGUI_INVALID_PARAMETERS + Parameters are not correctly specified +Please enter correct values and try again + + + SMESH_ADD_ALGORITHM + Algorithms + + + SMESH_ADD_ALGORITHM_TITLE + Algorithms Assignation + + + SMESH_ADD_ELEM0D + Add 0D Element + + + SMESH_ADD_ELEM0D_TITLE + Add 0D Element + + + SMESH_ADD_EDGE + Add Edge + + + SMESH_ADD_EDGE_TITLE + Add Edge + + + SMESH_ADD_HEXAS + Add Hexahedron + + + SMESH_ADD_HEXAS_TITLE + Add Hexahedron + + + SMESH_ADD_HYPOTHESIS + Hypothesis + + + SMESH_ADD_HYPOTHESIS_TITLE + Hypothesis Assignation + + + SMESH_ADD_HYP_WRN + "%1" assigned but: + + + + SMESH_ADD_POLYGON + Add polygon + + + SMESH_ADD_POLYGON_TITLE + Add polygon + + + SMESH_ADD_QUADRANGLE + Add Quadrangle + + + SMESH_ADD_QUADRANGLE_TITLE + Add Quadrangle + + + SMESH_ADD_QUADRATIC_EDGE_TITLE + Add Quadratic Edge + + + SMESH_ADD_QUADRATIC_HEXAHEDRON_TITLE + Add Quadratic Hexahedron + + + SMESH_ADD_QUADRATIC_PENTAHEDRON_TITLE + Add Quadratic Pentahedron + + + SMESH_ADD_QUADRATIC_PYRAMID_TITLE + Add Quadratic Pyramid + + + SMESH_ADD_QUADRATIC_QUADRANGLE_TITLE + Add Quadratic Quadrangle + + + SMESH_ADD_QUADRATIC_TETRAHEDRON_TITLE + Add Quadratic Tetrahedron + + + SMESH_ADD_QUADRATIC_TRIANGLE_TITLE + Add Quadratic Triangle + + + SMESH_ADD_SUBMESH + SubMesh Construction + + + SMESH_ADD_TETRAS + Add Tetrahedron + + + SMESH_ADD_TETRAS_TITLE + Add Tetrahedron + + + SMESH_ADD_TO_GROUP + Add to group + + + SMESH_ADD_TRIANGLE + Add Triangle + + + SMESH_ADD_TRIANGLE_TITLE + Add Triangle + + + SMESH_ANGLE + Angle + + + SMESH_ARGUMENTS + Arguments + + + SMESH_AUTO_GROUPS + Automatically create groups + + + SMESH_AVAILABLE + Available + + + SMESH_AVAILABLE_ALGORITHMS + Available algorithms + + + SMESH_AVAILABLE_HYPOTHESES + Available hypotheses + + + SMESH_AXIS + Axis + + + SMESH_BAD_SELECTION + No valid selection + + + SMESH_BAD_MESH_SELECTION + No valid mesh selection + + + SMESH_BOUNDARYEDGES + Boundary Edges + + + SMESH_BUILD_COMPOUND_TITLE + Create a Compound + + + SMESH_BUT_ADD + A&dd + + + SMESH_BUT_APPLY + &Apply + + + SMESH_BUT_CANCEL + &Cancel + + + SMESH_BUT_CLOSE + &Close + + + SMESH_BUT_CREATE + Create + + + SMESH_BUT_DELETE + Delete + + + SMESH_BUT_FILTER + Set &Filters + + + SMESH_BUT_HELP + &Help + + + SMESH_BUT_NEW + New + + + SMESH_BUT_NO + &No + + + SMESH_BUT_OK + &Ok + + + SMESH_BUT_OVERWRITE + Over&write + + + SMESH_BUT_APPLY_AND_CLOSE + A&pply and Close + + + SMESH_BUT_REMOVE + &Remove + + + SMESH_BUT_SORT + &Sort List + + + SMESH_BUT_YES + &Yes + + + SMESH_CANT_ADD_HYP + Can not assign "%1": + + + + SMESH_CANT_RM_HYP + Can not unassign "%1": + + + + SMESH_CHECK_COLOR + Color + + + SMESH_CLIPPING_FROM + From <--- + + + SMESH_CLIPPING_INTO + ---> Into + + + SMESH_CLIPPING_TITLE + Change Clipping + + + SMESH_COMPUTE_SUCCEED + Mesh computation succeed + + + SMESH_EVALUATE_SUCCEED + Mesh evaluation succeed + + + SMESH_CONTENT + Content + + + SMESH_CONTINUE_MESH_VISUALIZATION + It seems that there is not enough memory to show the mesh +so that the application may crash. Do you wish to continue visualization? + + + SMESH_COORDINATES + Coordinates + + + SMESH_COPY_ELEMENTS + Copy Elements + + + SMESH_COPY_GROUPS + Copy groups + + + SMESH_CREATE_ALGORITHMS + Create algorithms + + + SMESH_CREATE_COPY + Create a copy + + + SMESH_CREATE_GROUP_TITLE + Create Group + + + SMESH_CREATE_GEO_GROUP + Create Groups from Geometry + + + SMESH_CREATE_HYPOTHESES + Create hypotheses + + + SMESH_CREATE_MESH + Create a new mesh + + + SMESH_CREATE_POLYHEDRAL_VOLUME_TITLE + Create polyhedral volume + + + SMESH_DIAGONAL + Diagonal Inversion + + + SMESH_DIAGONAL_INVERSION_TITLE + Diagonal Inversion + + + SMESH_DISTANCE + Distance + + + SMESH_DRS_1 + MED file contains no mesh with the given name + + + SMESH_DRS_2 + MED file has overlapped ranges of element numbers, the numbers from the file are ignored + + + SMESH_DRS_3 + Some elements were skipped due to incorrect file data + + + SMESH_DRS_4 + The file is incorrect, some data is missed + + + SMESH_DRS_EMPTY + The file is empty, there is nothing to be published + + + SMESH_DX + dX + + + SMESH_DY + dY + + + SMESH_DZ + dZ + + + SMESH_ELEM0D + 0D Element + + + SMESH_EDGE + Edge + + + SMESH_EDGES_CONNECTIVITY_TITLE + Edges Connectivity + + + SMESH_EDIT_GROUP_TITLE + Edit Group + + + SMESH_EDIT_GEOMGROUP_AS_GROUP_TITLE + Edit Group as Standalone + + + SMESH_EDIT_HYPOTHESES + Hypotheses Assignation + + + SMESH_EDIT_USED + Used + + + SMESH_ELEMENTS + Elements + + + SMESH_ELEMENTS_COLOR + Mesh Element Color + + + SMESH_ELEMENTS_TYPE + Elements Type + + + SMESH_ELEMENT_TYPE + Element Type + + + SMESH_ERROR + Error + + + SMESH_ERR_SCALARBAR_PARAMS + Warning! The parameters is incorrect + + + SMESH_EXPORT_FAILED + Mesh export failed. +Probably, there is not enough space on disk. + + + SMESH_EXPORT_MED_DUPLICATED_GRP + There are duplicated group names in mesh "%1". +You can cancel exporting and rename them, +otherwise some group names in the resulting MED file +will not match ones in the study. +Do you want to continue ? + + + SMESH_EXPORT_MED_DUPLICATED_MESH_NAMES + There are some meshes with the same names in the selection. +The result file may be incorrect. +Do you want to continue ? + + + SMESH_EXPORT_MED_V2_1 + During export mesh with name - "%1" to MED 2.1 +polygons and polyhedrons elements will be missed +For correct export use MED 2.2 +Are you sure want to export to MED 2.1 ? + + + SMESH_EXPORT_MED_VERSION_COLLISION + MED version of the file "%1" +is unknown or doesn't match the selected version. +Overwrite the file? + + + SMESH_EXPORT_MED_MESH_NAMES_COLLISION + The selected file already contains +meshes with the following names: %1 +The result file may be incorrect. +Overwrite the file? + + + SMESH_EXPORT_STL1 + Mesh - "%1" does not contain triangles + + + SMESH_EXPORT_STL2 + Mesh - "%1" contains another than triangles elements, they are ignored during writing to STL + + + SMESH_EXPORT_UNV + During export mesh with name - "%1" to UNV + pyramid's elements will be missed + + + SMESH_EXTRUSION + Extrusion + + + SMESH_EXTRUSION_TO_DISTANCE + Extrusion To Distance + + + SMESH_EXTRUSION_ALONG_VECTOR + Extrusion Along Vector + + + SMESH_FACE + Face + + + SMESH_FEATUREANGLE + Feature Angle + + + SMESH_FEATUREEDGES + Feature Edges + + + SMESH_FILE_EXISTS + The file "%1" already exists. +Do you want to overwrite it or +add the exported data to its contents? + + + SMESH_FONT_ARIAL + Arial + + + SMESH_FONT_BOLD + Bold + + + SMESH_FONT_COURIER + Courier + + + SMESH_FONT_ITALIC + Italic + + + SMESH_FONT_SCALARBAR + Font + + + SMESH_FONT_SHADOW + Shadow + + + SMESH_FONT_TIMES + Times + + + SMESH_GEOM_GROUP + Geometry group + + + SMESH_GROUP + Group + + + SMESH_GROUP_GEOMETRY + Group on geometry + + + SMESH_GROUP_SELECTED + %1 Groups + + + SMESH_GROUP_STANDALONE + Standalone group + + + SMESH_GROUP_TYPE + Group type + + + SMESH_HEIGHT + Height: + + + SMESH_HEXAS + Hexahedron + + + SMESH_HILIGHT_COLOR + Highlight Color + + + SMESH_HORIZONTAL + Horizontal + + + SMESH_HYPOTHESES + Hypotheses + + + SMESH_HYP_1 + Algorithm misses a hypothesis + + + SMESH_HYP_10 + Hypothesis and submesh dimensions mismatch + + + SMESH_HYP_11 + Shape is neither the main one, nor its subshape, nor a valid group + + + SMESH_HYP_12 + Geometry mismatches algorithm's expectation\nCheck algorithm documentation for supported geometry + + + SMESH_HYP_13 + Algorithm can't work without shape + + + SMESH_HYP_2 + There are concurrent hypotheses on a shape + + + SMESH_HYP_3 + Hypothesis has a bad parameter value + + + SMESH_HYP_4 + Submesh is ignored as there is another algorithm of upper dimension generating %1D elements + + + SMESH_HYP_5 + Algorithm hides algorithm(s) of lower dimension by generating all-dimensions elements + + + SMESH_HYP_6 + Unknown fatal error at hypothesis definition + + + SMESH_HYP_7 + Hypothesis is not suitable in the current context + + + SMESH_HYP_8 + Non-conform mesh is produced using applied hypotheses + + + SMESH_HYP_9 + Such dimention hypothesis is already assigned to the shape + + + SMESH_ID_DIAGONAL + Id Edges + + + SMESH_ID_ELEMENTS + Id Elements + + + SMESH_ID_FACES + Id Faces + + + SMESH_ID_NODES + Id Nodes + + + SMESH_INCORRECT_INPUT + Incorrect input data! + + + SMESH_INFORMATION + Information + + + SMESH_INIT + Mesh + + + SMESH_INIT_MESH + Mesh Construction + + + SMESH_INSUFFICIENT_DATA + Insufficient input value + + + SMESH_LABELS + Labels: + + + SMESH_LABELS_COLORS_SCALARBAR + Colors && Labels + + + SMESH_LENGTH + Length + + + SMESH_MAKE_GROUPS + Generate groups + + + SMESH_MANIFOLDEDGES + Manifold Edges + + + SMESH_MAX + Max + + + SMESH_MEN_ALGORITHMS + Algorithms + + + SMESH_MEN_APPLIED_ALGORIHTMS + Applied Algorithms + + + SMESH_MEN_APPLIED_HYPOTHESIS + Applied Hypotheses + + + SMESH_MEN_COMPONENT + SMESH + + + SMESH_MEN_HYPOTHESIS + Hypotheses + + + SMESH_MEN_SubMeshesOnCompound + SubMeshes On Compound + + + SMESH_MEN_SubMeshesOnEdge + SubMeshes On Edge + + + SMESH_MEN_SubMeshesOnFace + SubMeshes On Face + + + SMESH_MEN_SubMeshesOnSolid + SubMeshes On Solid + + + SMESH_MEN_SubMeshesOnVertex + SubMeshes On Vertex + + + SMESH_AUTOMATIC + Automatic + + + SMESH_MANUAL + Manual + + + SMESH_MERGE_ELEMENTS + Merge elements + + + SMESH_MODE + Mode + + + SMESH_MERGED_ELEMENTS + %1 elements successfully merged. + + + SMESH_MERGED_NODES + %1 nodes successfully merged. + + + SMESH_NO_ELEMENTS_DETECTED + There are no elements to merge. + + + SMESH_NO_NODES_DETECTED + There are no nodes to merge. + + + SMESH_MERGE_NODES + Merge nodes + + + SMESH_MESH + Mesh + + + SMESH_MESHINFO_0DELEMS + 0D Elements + + + SMESH_MESHINFO_ALL_TYPES + Heterogenous + + + SMESH_MESHINFO_EDGES + Edges + + + SMESH_MESHINFO_ELEMENTS + Elements + + + SMESH_MESHINFO_ENTITIES + Entities + + + SMESH_MESHINFO_FACES + Faces + + + SMESH_MESHINFO_HEXAS + Hexahedrons + + + SMESH_MESHINFO_NAME + Name + + + SMESH_MESHINFO_NODES + Nodes + + + SMESH_MESHINFO_ORDER0 + Total + + + SMESH_MESHINFO_ORDER1 + Linear + + + SMESH_MESHINFO_ORDER2 + Quadratic + + + SMESH_MESHINFO_POLYEDRES + Polyhedrons + + + SMESH_MESHINFO_POLYGONES + Polygons + + + SMESH_MESHINFO_PRISMS + Prisms + + + SMESH_MESHINFO_PYRAS + Pyramids + + + SMESH_MESHINFO_QUADRANGLES + Quadrangles + + + SMESH_MESHINFO_TETRAS + Tetrahedrons + + + SMESH_MESHINFO_TITLE + Mesh Infos + + + SMESH_MESHINFO_TOTAL + Total + + + SMESH_MESHINFO_TRIANGLES + Triangles + + + SMESH_MESHINFO_TYPE + Type + + + SMESH_MESHINFO_VOLUMES + Volumes + + + SMESH_MIN + Min + + + SMESH_MOVE + Move + + + SMESH_MOVE_ELEMENTS + Move Elements + + + SMESH_MOVE_NODES_TITLE + Move Node + + + SMESH_NAME + Name + + + SMESH_NODES + Nodes + + + SMESH_NONMANIFOLDEDGES + Non Manifold Edges + + + SMESH_NORMAL + Normal + + + SMESH_NO_MESH_VISUALIZATION + There is not enough memory to show the mesh + + + SMESH_NUMBEROFCOLORS + Nb of colors: + + + SMESH_NUMBEROFLABELS + Nb of labels: + + + SMESH_NUMBEROFSTEPS + Number of steps: + + + SMESH_OBJECTS_SELECTED + %1_objects + + + SMESH_OBJECT_ALGORITHM + Algorithm + + + SMESH_OBJECT_GEOM + Geometrical Object + + + SMESH_OBJECT_HYPOTHESIS + Hypothesis + + + SMESH_OBJECT_MESH + Mesh + + + SMESH_OBJECT_MESHorSUBMESH + Mesh or SubMesh + + + SMESH_OPERATION_FAILED + Operation failed + + + SMESH_ORIENTATION + Orientation + + + SMESH_ORIENTATION_ELEMENTS_TITLE + Change Orientation + + + SMESH_OUTLINE_COLOR + Mesh Object Color + + + SMESH_PARAMETERS + Parameters + + + SMESH_PLANE + Plane + + + SMESH_POINT + Point + + + SMESH_POINT_1 + Point 1 + + + SMESH_POINT_2 + Point 2 + + + SMESH_BASE_POINT + Base Point + + + SMESH_POLYEDRE_CREATE_ERROR + Polyedron creation error + + + SMESH_POLYEDRON + Polyhedron + + + SMESH_POLYGON + Polygon + + + SMESH_POSITION_SIZE_SCALARBAR + Origin && Size + + + SMESH_DISTRIBUTION_SCALARBAR + Distribution + + + SMESH_SHOW_DISTRIBUTION_SCALARBAR + Show Distribution + + + SMESH_PRECISION + Precision + + + SMESH_PREFERENCES_SCALARBAR + Scalar Bar Preferences + + + SMESH_PREF_SELECTION + Preferences - Selection + + + SMESH_PRESELECTION + Preselection + + + SMESH_PRISM + Prism + + + SMESH_PROPERTIES_SCALARBAR + Scalar Bar Properties + + + SMESH_PYRAMID + Pyramid + + + SMESH_QUADRANGLE + Quadrangle + + + SMESH_QUADRATIC_EDGE + Quadratic Edge + + + SMESH_QUADRATIC_HEXAHEDRON + Quadratic Hexahedron + + + SMESH_QUADRATIC_PENTAHEDRON + Quadratic Pentahedron + + + SMESH_QUADRATIC_PYRAMID + Quadratic Pyramid + + + SMESH_QUADRATIC_QUADRANGLE + Quadratic Quadrangle + + + SMESH_QUADRATIC_TETRAHEDRON + Quadratic Tetrahedron + + + SMESH_QUADRATIC_TRIANGLE + Quadratic Triangle + + + SMESH_RANGE_MAX + Max value: + + + SMESH_RANGE_MIN + Min value: + + + SMESH_RANGE_SCALARBAR + Scalar Range + + + SMESH_REALLY_DELETE + Do you really want to delete this %1 object(s)? : %2 + + + SMESH_REMOVE + Remove + + + SMESH_REMOVE_ELEMENTS_TITLE + Remove Elements + + + SMESH_REMOVE_NODES_TITLE + Remove Nodes + + + SMESH_RENUMBERING + Renumbering + + + SMESH_RENUMBERING_ELEMENTS_TITLE + Renumbering elements + + + SMESH_RENUMBERING_NODES_TITLE + Renumbering nodes + + + SMESH_REVERSE + Reverse + + + SMESH_REVOLUTION + Revolution + + + SMESH_RM_HYP_WRN + "%1" unassigned but: + + + + SMESH_ROTATION + Rotation + + + SMESH_ROTATION_TITLE + Rotation about an axis + + + SMESH_SCALARBAR + Scalar Bar + + + SMESH_SEGMENTS + Segments + + + SMESH_SELECTION + Selection + + + SMESH_SELECT_FROM + Select From + + + SMESH_SELECT_WHOLE_MESH + Select whole mesh, submesh or group + + + SMESH_SET_COLOR + Color group + + + SMESH_SEWING + Sewing + + + SMESH_SMOOTHING + Smoothing + + + SMESH_STANDARD_MESHINFO_TITLE + Standard Mesh Infos + + + SMESH_SUBMESH + SubMesh + + + SMESH_SUBMESH_SELECTED + %1 SubMeshes + + + SMESH_SYMMETRY + Symmetry + + + SMESH_TETRAS + Tetrahedron + + + SMESH_TITLE + Title: + + + SMESH_TOLERANCE + Tolerance + + + SMESH_TRANSLATION + Translation + + + SMESH_SCALE_TITLE + Scale Transform + + + SMESH_DUPLICATE_TITLE + Duplicate Nodes + + + SMESH_SCALE + Scale + + + SMESH_SCALE_FACTOR + Scale Factor : + + + SMESH_SCALE_FACTOR_X + Scale Factor X : + + + SMESH_SCALE_FACTOR_Y + Scale Factor Y : + + + SMESH_SCALE_FACTOR_Z + Scale Factor Z : + + + SMESH_TRANSPARENCY_OPAQUE + ---> Opaque + + + SMESH_TRANSPARENCY_TITLE + Change Transparency + + + SMESH_TRANSPARENCY_TRANSPARENT + Transparent <--- + + + SMESH_TRIANGLE + Triangle + + + SMESH_UPDATEVIEW + Update View + + + SMESH_VALUE + Value + + + SMESH_VECTOR + Vector + + + SMESH_VERTICAL + Vertical + + + SMESH_DISTRIBUTION_COLORING_TYPE + Coloring Type + + + SMESH_MONOCOLOR + Monocolor + + + SMESH_DISTRIBUTION_COLOR + Distribution color: + + + SMESH_MULTICOLOR + Multicolor + + + SMESH_VISU_PROBLEM + Mesh visualization failed, probably due to lack of memory + + + SMESH_VISU_PROBLEM_CLEAR + Mesh visualization failed, no memory even to show a message, +so all visual data have been removed to let the application live. +Consider saving your work before application crash + + + SMESH_VOLUME + Volume + + + SMESH_WARNING + Warning + + + SMESH_WHAT_IS_TITLE + Mesh Element Info + + + SMESH_WIDTH + Width: + + + SMESH_WRN_ALGORITHM_ALREADYEXIST + Algorithm already exists + + + SMESH_WRN_COMPUTE_FAILED + Mesh computation failed + + + SMESH_WRN_EVALUATE_FAILED + Mesh evaluation failed + + + SMESH_WRN_EMPTY_NAME + Empty name is not valid + + + SMESH_WRN_HYPOTHESIS_ALREADYEXIST + Hypothesis already exists + + + SMESH_WRN_HYPOTHESIS_NOTEXIST + Hypothesis or Algorithm not exists + + + SMESH_WRN_MISSING_PARAMETERS + Missing parameters + + + SMESH_WRN_NO_AVAILABLE_DATA + No available data in selection + + + SMESH_WRN_SELECTIONMODE_DIAGONAL + Activate Link Selection Mode + + + SMESH_WRN_SELECTIONMODE_ELEMENTS + Activate Elements Selection Mode + + + SMESH_WRN_SELECTIONMODE_NODES + Activate Nodes Selection Mode + + + SMESH_WRN_VIEWER_VTK + Study frame with VTK Viewer must be activated + + + SMESH_WRN_SIZE_LIMIT_EXCEEDED + No automatic update of the presentation has been done: new mesh size (%1 elements) exceeds current size limit (%2 elements). +Please check preferences of Mesh module. + + + + SMESH_WRN_WARNING + Warning + + + SMESH_X + X + + + SMESH_X_SCALARBAR + X: + + + SMESH_Y + Y + + + SMESH_Y_SCALARBAR + Y: + + + SMESH_Z + Z + + + STATE_ALGO_MISSING + %3 %2D algorithm is missing + + + STATE_HYP_BAD_GEOMETRY + %3 %2D algorithm "%1" is assigned to geometry mismatching its expectation + + + STATE_HYP_BAD_PARAMETER + Hypothesis of %3 %2D algorithm "%1" has a bad parameter value + + + STATE_HYP_MISSING + %3 %2D algorithm "%1" misses %4D hypothesis + + + STATE_HYP_NOTCONFORM + %3 %2D algorithm "%1" would produce not conform mesh: global "Not Conform Mesh Allowed" hypotesis is missing + + + STB_ADV_INFO + Show base information about the mesh object + + + STB_ALL + All + + + STB_AREA + Area + + + STB_ASPECT + Aspect Ratio + + + STB_ASPECT_3D + Aspect Ratio 3D + + + STB_AUTO_COLOR + Auto color + + + STB_AUTO_UPD + Automatic update + + + STB_BUILD_COMPOUND + Build Compound Mesh + + + STB_CLIP + Clipping + + + STB_COLORS + Colors / Size + + + STB_COMPUTE + Compute + + + STB_PRECOMPUTE + Preview + + + STB_EVALUATE + Evaluate + + + STB_CONNECTION + Borders at Multi-Connection + + + STB_CONNECTION_2D + Borders at Multi-Connection 2D + + + STB_CONSTRUCT_GROUP + Construct Group + + + STB_CONV_TO_QUAD + Convert to/from quadratic + + + STB_2D_FROM_3D + Create boundary elements + + + STB_MESH_ORDER + Change submesh priority + + + STB_CREATE_GROUP + Create Group + + + STB_CREATE_GEO_GROUP + Create Groups from Geometry + + + STB_CREATE_MESH + Create Mesh + + + STB_CREATE_SUBMESH + Create Sub-mesh + + + STB_CUT + Cutting of quadrangles + + + STB_CUT_GROUP + Cut Groups + + + STB_DAT + Import DAT file + + + STB_DELETE + Delete + + + STB_DEL_GROUP + Delete Groups + + + STB_FACE_ORIENTATION + Orientation of faces + + + STB_DISABLE_AUTO_COLOR + Disable auto color + + + STB_DISPLAY_ONLY + Show only + + + STB_DISP_ENT + Display entity + + + STB_ELEM0D + 0D Element + + + STB_ELEMS0D + 0D Elements + + + STB_EDGE + Edge + + + STB_EDGES + Edges + + + STB_EDIT_GROUP + Edit Group + + + STB_EDIT_GEOMGROUP_AS_GROUP + Edit Group as Standalone + + + STB_EDIT_HYPO + Edit Hypothesis + + + STB_EDIT_MESHSUBMESH + Edit Mesh/Sub-mesh + + + STB_EXPORT_DAT + Export to DAT file + + + STB_EXPORT_MED + Export to MED file + + + STB_EXPORT_SAUV + Export to SAUV (ASCII) file + + + STB_EXPORT_STL + Export to STL file + + + STB_EXPORT_UNV + Export to UNV file + + + STB_EXTRUSION + Extrusion + + + STB_EXTRUSION_ALONG + Extrusion along a path + + + STB_FACES + Faces + + + STB_FREE_BORDER + Free Borders + + + STB_FREE_EDGE + Free Edges + + + STB_FREE_NODE + Free Nodes + + + STB_FREE_FACES + Free Faces + + + STB_GLOBAL_HYPO + Global Hypothesis + + + STB_HEXA + Hexahedron + + + STB_HIDE + Hide + + + STB_INT_GROUP + Intersect Groups + + + STB_INV + Diagonal Inversion + + + STB_LENGTH + Length + + + STB_LENGTH_2D + Length 2D + + + STB_MAP + Pattern mapping + + + STB_MAX_ELEMENT_LENGTH_2D + Element Diameter 2D + + + STB_MAX_ELEMENT_LENGTH_3D + Element Diameter 3D + + + STB_MED + Import MED file + + + STB_SAUV + Import SAUV (ASCII) file + + + STB_MERGE + Merge nodes + + + STB_MERGE_ELEMENTS + Merge elements + + + STB_MESH_THROU_POINT + Move Node + + + STB_MIN_ANG + Minimum Angle + + + STB_MOVE + Move Node + + + STB_NODE + Node + + + STB_NODES + Nodes + + + STB_NUM_ELEMENTS + Display Elements + + + STB_NUM_NODES + Display Nodes + + + STB_ORIENT + Orientation + + + STB_POLYGON + Polygon + + + STB_POLYHEDRON + Polyhedron + + + STB_PRECISION + Precision + + + STB_QUAD + Quadrangle + + + STB_QUADRATIC_EDGE + Quadratic Edge + + + STB_QUADRATIC_HEXAHEDRON + Quadratic Hexahedron + + + STB_QUADRATIC_PENTAHEDRON + Quadratic Pentahedron + + + STB_QUADRATIC_PYRAMID + Quadratic Pyramid + + + STB_QUADRATIC_QUADRANGLE + Quadratic Quadrangle + + + STB_QUADRATIC_TETRAHEDRON + Quadratic Tetrahedron + + + STB_QUADRATIC_TRIANGLE + Quadratic Triangle + + + STB_REMOVE_ELEMENTS + Remove elements + + + STB_REMOVE_NODES + Remove nodes + + + STB_REMOVE_ORPHAN_NODES + Remove orphan nodes + + + STB_RENAME + Rename + + + STB_RENUM_ELEMENTS + Renumbering elements + + + STB_RENUM_NODES + Renumbering nodes + + + STB_RESET + Reset + + + STB_SAVE_DISTRIBUTION + Save distribution to the file + - FULL_RECOMPUTE_QUESTION - + STB_SHOW_DISTRIBUTION + Show Distribution + + + STB_REVOLUTION + Revolution + + + STB_ROT + Rotation + + + STB_SCALAR_BAR + Scalar bar + + + STB_SCALAR_BAR_PROP + Scalar bar Properties + + + STB_SELECTION + Selection + + + STB_SEL_FILTER_LIB + Selection filters library + + + STB_SEW + Sewing + + + STB_SHADE + Shading + + + STB_SHOW + Show + + + STB_SHRINK + Shrink + + + STB_SKEW + Skew + + + STB_SMOOTH + Smoothing + + + STB_STD_INFO + Standard Mesh Infos + + + STB_SYM + Symmetry + + + STB_TAPER + Taper + + + STB_TETRA + Tetrahedron + + + STB_TRANS + Translation + + + STB_SCALE + Scale Transform + + + STB_DUPLICATE_NODES + Duplicate Nodes + + + STB_TRANSP + Transparency + + + STB_TRIANGLE + Triangle + + + STB_UNASSIGN + Unassign + + + STB_UNION + Union of triangles + + + STB_UNION2 + Union of two triangles + + + STB_UNV + Import UNV file + + + STB_UN_GROUP + Union Groups + + + STB_UNDERLYING_ELEMS + Create groups of entities from existing groups of superior dimensions + + + STB_UPDATE + Update + + + STB_VOLUMES + Volumes + + + STB_VOLUME_3D + Volume + + + STB_WARP + Warping angle + + + STB_WHAT_IS + Show information about the mesh node or element + + + STB_WIRE + Wireframe + + + TAPER_ELEMENTS + Taper + + + TB_ADD_REMOVE + Add/Remove Toolbar + + + TB_CTRL + Controls Toolbar + + + TB_DISP_MODE + Display Mode Toolbar + + + TB_HYPO + Hypotheses Toolbar + + + TB_MESH + Mesh Toolbar + + + TB_MODIFY + Modification Toolbar + + + TOP_ADV_INFO + Mesh Information + + + TOP_ALL + All + + + TOP_AREA + Area + + + TOP_ASPECT + Aspect Ratio + + + TOP_ASPECT_3D + Aspect Ratio 3D + + + TOP_AUTO_COLOR + Auto color + + + TOP_AUTO_UPD + Automatic update + + + TOP_BUILD_COMPOUND + Build Compound Mesh + + + TOP_CLIP + Clipping + + + TOP_COLORS + Colors / Size + + + TOP_COMPUTE + Compute + + + TOP_PRECOMPUTE + Preview + + + TOP_EVALUATE + Evaluate + + + TOP_CONNECTION + Borders at Multi-Connection + + + TOP_CONNECTION_2D + Borders at Multi-Connection 2D + + + TOP_CONSTRUCT_GROUP + Construct Group + + + TOP_CONV_TO_QUAD + Convert to/from quadratic + + + TOP_2D_FROM_3D + Create boundary elements + + + TOP_MESH_ORDER + Change submesh priority + + + TOP_CREATE_GROUP + Create Group + + + TOP_CREATE_GEO_GROUP + Create Groups from Geometry + + + TOP_CREATE_MESH + Create Mesh + + + TOP_CREATE_SUBMESH + Create Sub-mesh + + + TOP_CUT + Cutting of quadrangles + + + TOP_CUT_GROUP + Cut Groups + + + TOP_DAT + Import DAT file + + + TOP_DELETE + Delete + + + TOP_DEL_GROUP + Delete Groups + + + TOP_FACE_ORIENTATION + Orientation of faces + + + TOP_DISABLE_AUTO_COLOR + Disable auto color + + + TOP_DISPLAY_ONLY + Show only + + + TOP_DISP_ENT + Display entity + + + TOP_ELEM0D + 0D Element + + + TOP_ELEMS0D + 0D Elements + + + TOP_EDGE + Edge + + + TOP_EDGES + Edges + + + TOP_EDIT_GROUP + Edit Group + + + TOP_EDIT_GEOMGROUP_AS_GROUP + Edit Group as Standalone + + + TOP_EDIT_HYPO + Edit Hypothesis + + + TOP_EDIT_MESHSUBMESH + Edit Mesh/Sub-mesh + + + TOP_EXPORT_DAT + Export to DAT file + + + TOP_EXPORT_MED + Export to MED file + + + TOP_EXPORT_SAUV + Export to SAUV (ASCII) file + + + TOP_EXPORT_STL + Export to STL file + + + TOP_EXPORT_UNV + Export to UNV file + + + TOP_EXTRUSION + Extrusion + + + TOP_EXTRUSION_ALONG + Extrusion along a path + + + TOP_FACES + Faces + + + TOP_FREE_BORDER + Free Borders + + + TOP_FREE_EDGE + Free Edges + + + TOP_FREE_NODE + Free Nodes + + + TOP_FREE_FACES + Free Faces + + + TOP_GLOBAL_HYPO + Global Hypothesis + + + TOP_HEXA + Hexahedron + + + TOP_HIDE + Hide + + + TOP_INT_GROUP + Intersect Groups + + + TOP_INV + Diagonal Inversion + + + TOP_LENGTH + Length + + + TOP_LENGTH_2D + Length 2D + + + TOP_MAP + Pattern mapping + + + TOP_MAX_ELEMENT_LENGTH_2D + Element Diameter 2D + + + TOP_MAX_ELEMENT_LENGTH_3D + Element Diameter 3D + + + TOP_MED + Import MED file + + + TOP_SAUV + Import SAUV (ASCII) file + + + TOP_MERGE + Merge nodes + + + TOP_MERGE_ELEMENTS + Merge elements + + + TOP_MESH_THROU_POINT + Move Node + + + TOP_MIN_ANG + Minimum Angle + + + TOP_MOVE + Move Node + + + TOP_NODE + Node + + + TOP_NODES + Nodes + + + TOP_NUM_ELEMENTS + Display Elements + + + TOP_NUM_NODES + Display Nodes + + + TOP_ORIENT + Orientation + + + TOP_POLYGON + Polygon + + + TOP_POLYHEDRON + Polyhedron + + + TOP_PRECISION + Precision + + + TOP_QUAD + Quadrangle + + + TOP_QUADRATIC_EDGE + Quadratic Edge + + + TOP_QUADRATIC_HEXAHEDRON + Quadratic Hexahedron + + + TOP_QUADRATIC_PENTAHEDRON + Quadratic Pentahedron + + + TOP_QUADRATIC_PYRAMID + Quadratic Pyramid + + + TOP_QUADRATIC_QUADRANGLE + Quadratic Quadrangle + + + TOP_QUADRATIC_TETRAHEDRON + Quadratic Tetrahedron + + + TOP_QUADRATIC_TRIANGLE + Quadratic Triangle + + + TOP_REMOVE_ELEMENTS + Remove elements + + + TOP_REMOVE_NODES + Remove nodes + + + TOP_REMOVE_ORPHAN_NODES + Remove orphan nodes + + + TOP_RENAME + Rename + + + TOP_RENUM_ELEMENTS + Renumbering elements + + + TOP_RENUM_NODES + Renumbering nodes + + + TOP_RESET + Reset + + + TOP_SAVE_DISTRIBUTION + Export distribution + + + TOP_SHOW_DISTRIBUTION + Show Distribution + + + TOP_REVOLUTION + Revolution + + + TOP_ROT + Rotation + + + TOP_SCALAR_BAR + Scalar bar + + + TOP_SCALAR_BAR_PROP + Scalar bar Properties + + + TOP_SELECTION + Selection + + + TOP_SEL_FILTER_LIB + Selection filters library + + + TOP_SEW + Sewing + + + TOP_SHADE + Shading + + + TOP_SHOW + Show + + + TOP_SHRINK + Shrink + + + TOP_SKEW + Skew + + + TOP_SMOOTH + Smoothing + + + TOP_STD_INFO + Standard Mesh Infos + + + TOP_SYM + Symmetry + + + TOP_TAPER + Taper + + + TOP_TETRA + Tetrahedron + + + TOP_TRANS + Translation + + + TOP_SCALE + Scale Transform + + + TOP_DUPLICATE_NODES + Duplicate Nodes + + + TOP_TRANSP + Transparency + + + TOP_TRIANGLE + Triangle + + + TOP_UNASSIGN + Unassign + + + TOP_UNION + Union of triangles + + + TOP_UNION2 + Union of two triangles + + + TOP_UNV + Import UNV file + + + TOP_UN_GROUP + Union Groups + + + TOP_UNDERLYING_ELEMS + Create groups of entities from existing groups of superior dimensions + + + TOP_UPDATE + Update + + + TOP_VOLUMES + Volumes + + + TOP_VOLUME_3D + Volume + + + TOP_WARP + Warping angle + + + TOP_WHAT_IS + Mesh Element Information + + + TOP_WIRE + Wireframe + + + UNKNOWN_CONTROL + Unknown + + + VOLUME_3D_ELEMENTS + Volume + + + WARP_ELEMENTS + Warping + + + MEN_FILE_INFO + MED File Information + + + SMESH_WRN_NO_APPROPRIATE_SELECTION + No appropriate objects selected + + + MEN_CLEAR_MESH + Clear Mesh Data + + + TOP_CLEAR_MESH + Clear Mesh Data + + + STB_CLEAR_MESH + Clear Mesh Data + + + SMESH_IMPORT_MESH + Import mesh data from files + + + SMESH_ERR_NOT_SUPPORTED_FORMAT + Unsupported file format + + + SMESH_ERR_UNKNOWN_IMPORT_ERROR + Unknown error + + + SMESH_IMPORT_ERRORS + Import operation has finished with errors: + + + SMESH_DRS_SOME_EMPTY + One or more mesh files were empty, data has not been published + + + NO_MESH_SELECTED + No mesh selected + + + SMESH_PREF_def_precision + Default precision + + + SMESH_PREF_length_precision + Length precision + + + SMESH_PREF_angle_precision + Angular precision + + + SMESH_PREF_len_tol_precision + Length tolerance precision + + + SMESH_PREF_parametric_precision + Parametric precision + + + SMESH_PREF_area_precision + Area precision + + + FULL_RECOMPUTE_QUESTION + The mesh has been edited since a last total re-compute that may prevent successful computation. Do you wish to re-compute the mesh totally to discard the modifications? - - - - SMESH_PREF_vol_precision - Volume precision - - - SMESH_PRECISION_HINT - + + + + SMESH_PREF_vol_precision + Volume precision + + + SMESH_PRECISION_HINT + Input value precision can be adjusted using -'%1' parameter in Mesh module preferences. - - - - SMESHGUI - - NOT_A_VTK_VIEWER - This command is available in VTK viewer only +'%1' parameter in Mesh module preferences. + + + REMOVE_ORPHAN_NODES_QUESTION + Do you really want to remove all orphan nodes? + + + NB_NODES_REMOVED + Removed %1 node(s). + + + SMESH_SAVE_DISTRIBUTION + Export Distribution + + + SMESH_PLUGINS_OTHER + SMESH plugins + + + + SMESHGUI + + NOT_A_VTK_VIEWER + This command is available in VTK viewer only Please, create VTK viewer and try again - - - PREF_AUTO_GROUPS - Automatically create groups for MED export - - - PREF_GROUP_SEGMENT_LENGTH - Automatic parameters - - - PREF_SEGMENT_LENGTH - Ratio Bounding Box Diagonal / Max Size - - - PREF_NB_SEGMENTS - Default Number of Segments - - - PREF_AUTO_UPDATE - Automatic update - - - PREF_BACKFACE - Back face - - - PREF_COLOR - Color - - - PREF_ORIENTATION_COLOR - Color - - - PREF_ORIENTATION_3D_VECTORS - 3D vectors - - - PREF_ORIENTATION_SCALE - Scale - - - PREF_DISPLAY_ENTITY - Display entity - - - QUADRATIC_REPRESENT_MODE - Representation of the 2D quadratic elements - - - MAX_ARC_ANGLE - Maximum angle - - - PREF_DISPLAY_MODE - Display mode - - - PREF_ELEMENTS - Elements - - - PREF_ELEMENT_COLOR - Element color - - - PREF_FILL - Fill - - - PREF_NOTIFY_MODE - Show a computation result notification - - - SMESH_PREF_GROUP_PRECISION - Input fields precision - - - PREF_GROUP_ELEMENTS - Elements - - - PREF_GROUP_EXPORT - Mesh export - - - PREF_GROUP_FACES_ORIENTATION - Orientation of faces - - - PREF_GROUP_COMPUTE - Mesh computation - - - PREF_GROUP_NODES - Nodes - - - PREF_GROUP_PRECISION - Precision - - - PREF_GROUP_PRESELECTION - Preselection - - - PREF_GROUP_QUALITY - Quality controls - - - PREF_GROUP_SELECTION - Selection - - - PREF_GROUP_UPDATE - Update - - - PREF_HIGHLIGHT_COLOR - Highlight color - - - PREF_LABELS_COLOR - Labels color - - - PREF_MARKER_SCALE - Scale of marker - - - PREF_NODES - Nodes - - - PREF_OBJECTS - Objects - - - PREF_OBJECT_COLOR - Object color - - - PREF_OUTLINE - Outline - - - PREF_PRECISION_USE - Use precision - - - PREF_PRECISION_VALUE - Number of digits after point - - - PREF_RENUMBER - Automatic renumbering - - - PREF_SHRINK_COEFF - Shrink coef. - - - PREF_TAB_GENERAL - General - - - PREF_TAB_MESH - Mesh - - - PREF_TAB_SELECTION - Selection - - - PREF_TITLE_COLOR - Title color - - - PREF_TYPE_OF_MARKER - Type of marker - - - PREF_COLOR_0D - 0D elements - - - PREF_SIZE_0D - Size of 0D elements - - - PREF_WIDTH - Width - - - - SMESHGUI_AddQuadraticElementDlg - - SMESH_ADD_QUADRATIC_EDGE - Add Quadratic Edge - - - SMESH_ADD_QUADRATIC_HEXAHEDRON - Add Quadratic Hexahedron - - - SMESH_ADD_QUADRATIC_PENTAHEDRON - Add Quadratic Pentahedron - - - SMESH_ADD_QUADRATIC_PYRAMID - Add Quadratic Pyramid - - - SMESH_ADD_QUADRATIC_QUADRANGLE - Add Quadratic Quadrangle - - - SMESH_ADD_QUADRATIC_TETRAHEDRON - Add Quadratic Tetrahedron - - - SMESH_ADD_QUADRATIC_TRIANGLE - Add Quadratic Triangle - - - SMESH_CORNER_NODES - Corner Nodes: - - - SMESH_FIRST - First - - - SMESH_LAST - Last - - - SMESH_MIDDLE - Middle - - - - SMESHGUI_BuildCompoundDlg - - COMPOUND - Compound - - - COMPOUND_MESH - Compound_Mesh - - - CREATE_COMMON_GROUPS - Create common groups for initial meshes - - - MERGE_NODES_AND_ELEMENTS - Merge coincident nodes and elements - - - MESHES - Meshes - - - PROCESSING_IDENTICAL_GROUPS - Processing identical groups - - - RENAME - Rename - - - RESULT_NAME - Result name - - - UNITE - Unite - - - - SMESHGUI_ChangeOrientationDlg - - CAPTION - Modification of orientation - - - - SMESHGUI_ComputeDlg - - CAPTION - Compute mesh failed - - - CONSTRUCTOR - Compute mesh - - - EVAL_DLG - Evaluate mesh - - - ERRORS - Errors - - - MEMORY_LACK - Memory allocation problem - - - PUBLISH_SHAPE - Publish SubShape - - - SHOW_SHAPE - Show SubShape - - - SHOW_BAD_MESH - Show bad Mesh - - - - SMESHGUI_PrecomputeDlg - - CAPTION - Preview and Compute mesh - - - PREVIEW - Preview - - - PREVIEW_1 - 1D Mesh - - - PREVIEW_2 - 2D Mesh - - - COMPUTE - Compute - - - - SMESHGUI_PrecomputeOp - - CLEAR_SUBMESH_QUESTION - A temporary submeshes on the selected geometry - created during preview operation. - Do you want to remove all this submeshes? - - - SMESH_WRN_NOTHING_PREVIEW - No mesh preview is available - - - SMESH_REJECT_MESH_ORDER - The submesh priority changed during preview operation. + + + PREF_AUTO_GROUPS + Automatically create groups for MED export + + + PREF_GROUP_SEGMENT_LENGTH + Automatic parameters + + + PREF_SEGMENT_LENGTH + Ratio Bounding Box Diagonal / Max Size + + + PREF_NB_SEGMENTS + Default Number of Segments + + + PREF_AUTO_UPDATE + Automatic update + + + PREF_UPDATE_LIMIT + Size limit (elements) + + + PREF_UPDATE_LIMIT_NOLIMIT + No limit + + + PREF_BACKFACE + Back face + + + PREF_COLOR + Color + + + PREF_ORIENTATION_COLOR + Color + + + PREF_ORIENTATION_3D_VECTORS + 3D vectors + + + PREF_ORIENTATION_SCALE + Scale + + + PREF_DISPLAY_ENTITY + Display entity + + + QUADRATIC_REPRESENT_MODE + Representation of the 2D quadratic elements + + + MAX_ARC_ANGLE + Maximum angle + + + PREF_DISPLAY_MODE + Display mode + + + PREF_ELEMENTS + Elements + + + PREF_ELEMENT_COLOR + Element color + + + PREF_FILL + Fill + + + PREF_NOTIFY_MODE + Show a computation result notification + + + PREF_NOTIFY_NEVER + Never + + + PREF_NOTIFY_ERROR + Errors only + + + PREF_NOTIFY_ALWAYS + Always + + + PREF_ELEM_INFO + Mesh element information + + + PREF_ELEM_INFO_SIMPLE + Simple + + + PREF_ELEM_INFO_TREE + Tree + + + SMESH_PREF_GROUP_PRECISION + Input fields precision + + + PREF_GROUP_ELEMENTS + Elements + + + PREF_GROUP_EXPORT + Mesh export + + + PREF_GROUP_FACES_ORIENTATION + Orientation of faces + + + PREF_GROUP_COMPUTE + Mesh computation + + + PREF_GROUP_NODES + Nodes + + + PREF_GROUP_GROUPS + Groups + + + PREF_GRP_NAMES + Names color + + + PREF_GROUP_PRECISION + Precision + + + PREF_GROUP_PRESELECTION + Preselection + + + PREF_GROUP_QUALITY + Quality controls + + + PREF_GROUP_SELECTION + Selection + + + PREF_GROUP_INFO + Mesh information + + + PREF_HIGHLIGHT_COLOR + Highlight color + + + PREF_LABELS_COLOR + Labels color + + + PREF_MARKER_SCALE + Scale of marker + + + PREF_NODES + Nodes + + + PREF_OBJECTS + Objects + + + PREF_OBJECT_COLOR + Object color + + + PREF_OUTLINE + Outline + + + PREF_PRECISION_USE + Use precision + + + PREF_PRECISION_VALUE + Number of digits after point + + + PREF_RENUMBER + Automatic renumbering + + + PREF_SHRINK_COEFF + Shrink coef. + + + PREF_TAB_GENERAL + General + + + PREF_TAB_MESH + Mesh + + + PREF_TAB_SELECTION + Selection + + + PREF_TITLE_COLOR + Title color + + + PREF_TYPE_OF_MARKER + Type of marker + + + PREF_COLOR_0D + 0D elements + + + PREF_SIZE_0D + Size of 0D elements + + + PREF_WIDTH + Width + + + + SMESHGUI_AddQuadraticElementDlg + + SMESH_ADD_QUADRATIC_EDGE + Add Quadratic Edge + + + SMESH_ADD_QUADRATIC_HEXAHEDRON + Add Quadratic Hexahedron + + + SMESH_ADD_QUADRATIC_PENTAHEDRON + Add Quadratic Pentahedron + + + SMESH_ADD_QUADRATIC_PYRAMID + Add Quadratic Pyramid + + + SMESH_ADD_QUADRATIC_QUADRANGLE + Add Quadratic Quadrangle + + + SMESH_ADD_QUADRATIC_TETRAHEDRON + Add Quadratic Tetrahedron + + + SMESH_ADD_QUADRATIC_TRIANGLE + Add Quadratic Triangle + + + SMESH_CORNER_NODES + Corner Nodes: + + + SMESH_FIRST + First + + + SMESH_LAST + Last + + + SMESH_MIDDLE + Middle + + + + SMESHGUI_BuildCompoundDlg + + COMPOUND + Compound + + + COMPOUND_MESH + Compound_Mesh + + + CREATE_COMMON_GROUPS + Create common groups for initial meshes + + + MERGE_NODES_AND_ELEMENTS + Merge coincident nodes and elements + + + MESHES + Meshes + + + PROCESSING_IDENTICAL_GROUPS + Processing identical groups + + + RENAME + Rename + + + RESULT_NAME + Result name + + + UNITE + Unite + + + + SMESHGUI_ChangeOrientationDlg + + CAPTION + Modification of orientation + + + + SMESHGUI_ComputeDlg + + CAPTION + Compute mesh failed + + + CONSTRUCTOR + Compute mesh + + + EVAL_DLG + Evaluate mesh + + + ERRORS + Errors + + + MEMORY_LACK + Memory allocation problem + + + PUBLISH_SHAPE + Publish SubShape + + + SHOW_SHAPE + Show SubShape + + + SHOW_BAD_MESH + Show bad Mesh + + + + SMESHGUI_PrecomputeDlg + + CAPTION + Preview and Compute mesh + + + PREVIEW + Preview + + + PREVIEW_1 + 1D Mesh + + + PREVIEW_2 + 2D Mesh + + + COMPUTE + Compute + + + + SMESHGUI_PrecomputeOp + + CLEAR_SUBMESH_QUESTION + Temporary submeshes on the selected geometry +were created during preview operation. +Do you want to remove all these submeshes? + + + SMESH_WRN_NOTHING_PREVIEW + No mesh preview is available + + + SMESH_REJECT_MESH_ORDER + The submesh priority changed during preview operation. Do you want to restore original submesh priority? - - - - SMESHGUI_ConvToQuadDlg - - CAPTION - Convert to/from quadratic - - - MEDIUMNDS - Medium nodes on geometry - - - MESH - Mesh - - - RADIOBTN_1 - Convert to quadratic - - - RADIOBTN_2 - Convert from quadratic - - - - SMESHGUI_ConvToQuadOp - - MESH_IS_NOT_SELECTED - Mesh is not selected + + + + SMESHGUI_ConvToQuadDlg + + CAPTION + Convert to/from quadratic + + + MEDIUMNDS + Medium nodes on geometry + + + MESH + Mesh + + + RADIOBTN_1 + Convert to quadratic + + + RADIOBTN_2 + Convert from quadratic + + + + SMESHGUI_ConvToQuadOp + + MESH_IS_NOT_SELECTED + Mesh is not selected Please specify it and try again - - - REF_IS_NULL - No valid mesh object selected - - - - SMESHGUI_Make2DFrom3DDlg - - CAPTION - Create 2D mesh from 3D - - - - SMESHGUI_CreatePatternDlg - - CAPTION - Pattern Creation - - - DEFAULT_2D - Pattern_2d - - - DEFAULT_3D - Pattern_3d - - - ERROR_OF_CREATION - Internal error occurs during pattern creation -Please verify validity of entered information - - - ERROR_OF_SAVING - Internal error occurs during pattern saving. Please verify -\free disk space and your write permission to this file - - - ERR_LOADF_CANT_PROJECT - Impossible to perform projection of nodes to the face - - - ERR_LOADF_CLOSED_FACE - It is impossible to create pattern from face having seam edge - - - ERR_LOADF_NARROW_FACE - It is impossible to create pattern from narrow face - - - ERR_LOADV_BAD_SHAPE - Pattern can be created from closed shell or solid with 6 faces only - - - ERR_LOADV_COMPUTE_PARAMS - It is impossible to compute point parameters - - - ERR_LOAD_EMPTY_SUBMESH - There are no elements to create pattern - - - MESH_OR_SUBMESH - Mesh or SubMesh - - - PATTERN - Pattern - - - PATTERN_FILT - Pattern files(*.smp) - - - PATTERN_NAME - Pattern name - - - PATTERN_TYPE - Pattern type - - - PROJECT - Project nodes on the face - - - SAVE - Save... - - - SAVE_PATTERN - Save Pattern - - - - SMESHGUI_CreatePolyhedralVolumeDlg - - FACES_BY_NODES - Faces by nodes - - - SMESH_POLYEDRE_CREATE_ERROR - Polyhedron creation error. - - - SMESH_POLYEDRE_PREVIEW - Polyhedron preview - - - - SMESHGUI_CuttingOfQuadsDlg - - CAPTION - Cutting of quadrangles - - - - SMESHGUI_DeleteGroupDlg - - CAPTION - Delete groups with contents - - - NO_SELECTED_GROUPS - There are no selected groups -Please select a groups and try again - - - SELECTED_GROUPS - Selected groups - - - - SMESHGUI_EditMeshDlg - - COINCIDENT_ELEMENTS - Coincident elements - - - COINCIDENT_NODES - Coincident nodes - - - DETECT - Detect - - - EDIT_SELECTED_GROUP - Edit selected group - - - SELECT_ALL - Select all - - - - SMESHGUI_ExtrusionAlongPathDlg - - BAD_SHAPE_TYPE - The shape selected for the path is not edge - - - CANT_GET_TANGENT - Can't get tangent for one of the path nodes - - - EXTRUSION_1D - Extrusion of 1D elements - - - EXTRUSION_2D - Extrusion of 2D elements - - - EXTRUSION_ALONG_PATH - Extrusion along a path - - - EXTR_BAD_STARTING_NODE - Wrong path starting node - - - LINEAR_ANGLES - Linear variation of the angles - - - NO_ELEMENTS_SELECTED - No mesh elements are selected for extrusion - - - SELECTED_PATH_IS_NOT_EDGE - Path mesh should be of edge type - - - SMESH_ANGLES - Rotation Angles - - - SMESH_BASE_POINT - Base Point - - - SMESH_PATH - Path - - - SMESH_PATH_MESH - Mesh or submesh - - - SMESH_PATH_SHAPE - Shape (edge) - - - SMESH_PATH_START - Start node - - - SMESH_USE_ANGLES - Use Angles - - - SMESH_USE_BASE_POINT - Use Base Point - - - WRONG_ANGLES_NUMBER - The number of angles should correspond to the number of path nodes - - - - SMESHGUI_ExtrusionDlg - - EXTRUSION_1D - Extrusion of 1D elements - - - EXTRUSION_2D - Extrusion of 2D elements - - - EXTRUSION_ALONG_LINE - Extrusion along a line - - - - SMESHGUI_FilterDlg - - BAD_SHAPE_NAME - There is no "%1" geometrical object in the current study + + + REF_IS_NULL + No valid mesh object selected + + + + SMESHGUI_CreatePatternDlg + + CAPTION + Pattern Creation + + + DEFAULT_2D + Pattern_2d + + + DEFAULT_3D + Pattern_3d + + + ERROR_OF_CREATION + Internal error occurs during pattern creation +Please verify validity of entered information + + + ERROR_OF_SAVING + Internal error occurs during pattern saving. Please verify +\free disk space and your write permission to this file + + + ERR_LOADF_CANT_PROJECT + Impossible to perform projection of nodes to the face + + + ERR_LOADF_CLOSED_FACE + It is impossible to create pattern from face having seam edge + + + ERR_LOADF_NARROW_FACE + It is impossible to create pattern from narrow face + + + ERR_LOADV_BAD_SHAPE + Pattern can be created from closed shell or solid with 6 faces only + + + ERR_LOADV_COMPUTE_PARAMS + It is impossible to compute point parameters + + + ERR_LOAD_EMPTY_SUBMESH + There are no elements to create pattern + + + MESH_OR_SUBMESH + Mesh or SubMesh + + + PATTERN + Pattern + + + PATTERN_FILT + Pattern files(*.smp) + + + PATTERN_NAME + Pattern name + + + PATTERN_TYPE + Pattern type + + + PROJECT + Project nodes on the face + + + SAVE + Save... + + + SAVE_PATTERN + Save Pattern + + + + SMESHGUI_CreatePolyhedralVolumeDlg + + FACES_BY_NODES + Faces by nodes + + + SMESH_POLYEDRE_CREATE_ERROR + Polyhedron creation error. + + + SMESH_POLYEDRE_PREVIEW + Polyhedron preview + + + + SMESHGUI_CuttingOfQuadsDlg + + CAPTION + Cutting of quadrangles + + + + SMESHGUI_DeleteGroupDlg + + CAPTION + Delete groups with contents + + + NO_SELECTED_GROUPS + There are no selected groups +Please select a group and try again + + + SELECTED_GROUPS + Selected groups + + + + SMESHGUI_MergeDlg + + COINCIDENT_ELEMENTS + Coincident elements + + + COINCIDENT_NODES + Coincident nodes + + + DETECT + Detect + + + EDIT_SELECTED_GROUP + Edit selected group + + + SELECT_ALL + Select all + + + EXCLUDE_GROUPS + Exclude Groups + + + + SMESHGUI_ExtrusionAlongPathDlg + + BAD_SHAPE_TYPE + The shape selected for the path is not edge + + + CANT_GET_TANGENT + Can't get tangent for one of the path nodes + + + EXTRUSION_1D + Extrusion of 1D elements + + + EXTRUSION_2D + Extrusion of 2D elements + + + EXTRUSION_ALONG_PATH + Extrusion along a path + + + EXTR_BAD_STARTING_NODE + Wrong path starting node + + + LINEAR_ANGLES + Linear variation of the angles + + + NO_ELEMENTS_SELECTED + No mesh elements are selected for extrusion + + + SELECTED_PATH_IS_NOT_EDGE + Path mesh should be of edge type + + + SMESH_ANGLES + Rotation Angles + + + SMESH_BASE_POINT + Base Point + + + SMESH_PATH + Path + + + SMESH_PATH_MESH + Mesh or submesh + + + SMESH_PATH_SHAPE + Shape (edge) + + + SMESH_PATH_START + Start node + + + SMESH_USE_ANGLES + Use Angles + + + SMESH_USE_BASE_POINT + Use Base Point + + + WRONG_ANGLES_NUMBER + The number of angles should correspond to the number of path nodes + + + + SMESHGUI_ExtrusionDlg + + EXTRUSION_1D + Extrusion of 1D elements + + + EXTRUSION_2D + Extrusion of 2D elements + + + EXTRUSION_ALONG_LINE + Extrusion along a line + + + + SMESHGUI_FilterDlg + + BAD_SHAPE_NAME + There is no "%1" geometrical object in the current study Please select valid object and try again - - - CURRENT_DIALOG - Current Dialog - - - EDGES_TLT - Filter for Edges - - - FACES_TLT - Filter for Faces - - - MESH - Mesh - - - NODES_TLT - Filter for Nodes - - - SELECTION - Initial Selection - - - SET_IN_VIEWER - Insert filter in viewer - - - SHAPE_IS_NOT_A_CYLINDER - "%1" is not a cylinderical face + + + CURRENT_DIALOG + Current Group + + + EDGES_TLT + Filter for Edges + + + FACES_TLT + Filter for Faces + + + MESH + Mesh + + + NODES_TLT + Filter for Nodes + + + SELECTION + Initial Selection + + + SET_IN_VIEWER + Insert filter in viewer + + + SHAPE_IS_NOT_A_CYLINDER + "%1" is not a cylinderical face Please select a cylindrical face and try again - - - SHAPE_IS_NOT_A_FACE - "%1" is not a face + + + SHAPE_IS_NOT_A_FACE + "%1" is not a face Please select a face and try again - - - SHAPE_IS_NOT_A_PLANE - "%1" is not a plane + + + SHAPE_IS_NOT_A_PLANE + "%1" is not a plane Please select a plane and try again - - - SOURCE - Source - - - TLT - Selection filter - - - VOLUMES_TLT - Filter for Volumes - - - - SMESHGUI_FilterLibraryDlg - - ADD - Add - - - ADD_TO_TLT - Add selection filter to library - - - ALL_FILES_FILTER - All Files (*.*) - - - ASSIGN_NEW_NAME - Library already contains filter with name "%1" -New name "%2" is assigned to added filter - - - COPY_FROM_TLT - Copy selection filter from library - - - DELETE - Delete - - - EDGE - Edge - - - EDIT_LIB_TLT - Selection filter library - - - ELEMENT - Element - - - EMPTY_FILTER_NAME - Name of the filter is empty + + + FACE_ID_NOT_SELECTED + Mesh face is not selected +Please specify it and try again + + + NOT_FACE_ID + "%1" is not an ID of a mesh face. +Please select a face and try again + + + SOURCE + Source + + + TLT + Selection filter + + + VOLUMES_TLT + Filter for Volumes + + + + SMESHGUI_FilterLibraryDlg + + ADD + Add + + + ADD_TO_TLT + Add selection filter to library + + + ALL_FILES_FILTER + All Files (*.*) + + + ASSIGN_NEW_NAME + Library already contains filter with name "%1" +New name "%2" is assigned to added filter + + + COPY_FROM_TLT + Copy selection filter from library + + + DELETE + Delete + + + EDGE + Edge + + + EDIT_LIB_TLT + Selection filter library + + + ELEMENT + Element + + + EMPTY_FILTER_NAME + Name of the filter is empty Please enter a non-empty name - - - ERROR_FILTER_NAME - Name of the filter is not unique + + + ERROR_FILTER_NAME + Name of the filter is not unique Please enter other name - - - ERROR_LOAD - It is impossible to load library + + + ERROR_LOAD + It is impossible to load library Please check library file name and attributes - - - ERROR_OF_ADDING - Internal error occurs during adiing new filter in library. + + + ERROR_OF_ADDING + Internal error occurs during adiing new filter in library. Please verify validity of entered information - - - ERROR_OF_COPYING - Internal error occurs during copying filter from library. + + + ERROR_OF_COPYING + Internal error occurs during copying filter from library. Please verify validity of entered information - - - ERROR_OF_DELETING - Internal error occurs during deleting filter from library. + + + ERROR_OF_DELETING + Internal error occurs during deleting filter from library. Please verify validity of entered information - - - ERROR_OF_EDITING - Internal error occurs during editing filter library. + + + ERROR_OF_EDITING + Internal error occurs during editing filter library. Please verify validity of entered information - - - ERROR_OF_SAVING - Internal error occurs during saving filter library + + + ERROR_OF_SAVING + Internal error occurs during saving filter library Please check input data and try again - - - FACE - Face - - - FILTER - Filter - - - FILTER_NAME - Filter name - - - FILTER_NAMES - Names of filters - - - LIBRARY_FILE - Library file name - - - LIBRARY_IS_NOT_LOADED - Library is not loaded. Please load library and try again - - - LIB_NAME - FilterLib.xml - - - NODE - Node - - - NO_PERMISSION - You do not have write permission to this file - - - OPEN_LIBRARY - Open library - - - SELECTION - Selection - - - VOLUME - Volume - - - XML_FILT - XML files(*.xml) - - - - SMESHGUI_FilterTable - - ADD - Add - - - ADDITIONAL_PARAMETERS - Additional parameters - - - ADD_TO - Add to... - - - AND - And - - - AREA - Area - - - ASPECT_RATIO - Aspect ratio - - - ASPECT_RATIO_3D - Aspect ratio 3D - - - BAD_ORIENTED_VOLUME - Bad oriented volume - - - BELONG_TO_CYLINDER - Belong to Cylinder - - - BELONG_TO_GENSURFACE - Belong to Surface - - - BELONG_TO_GEOM - Belong to Geom - - - BELONG_TO_PLANE - Belong to Plane - - - BINARY - Binary - - - CLEAR - Clear - - - COMPARE - Compare - - - COPY_FROM - Copy from... - - - CRITERION - Criterion - - - EDGES - Edges - - - ENTITY_TYPE - Entity type - - - EQUAL_TO - Equal to - - - ERROR - Threshold value is not correctly specified + + + FACE + Face + + + FILTER + Filter + + + FILTER_NAME + Filter name + + + FILTER_NAMES + Names of filters + + + LIBRARY_FILE + Library file name + + + LIBRARY_IS_NOT_LOADED + Library is not loaded. Please load library and try again + + + LIB_NAME + FilterLib.xml + + + NODE + Node + + + NO_PERMISSION + You do not have write permission to this file + + + OPEN_LIBRARY + Open library + + + SELECTION + Selection + + + VOLUME + Volume + + + XML_FILT + XML files(*.xml) + + + + SMESHGUI_FilterTable + + ADD + Add + + + ADDITIONAL_PARAMETERS + Additional parameters + + + ADD_TO + Add to... + + + AND + And + + + AREA + Area + + + ASPECT_RATIO + Aspect ratio + + + ASPECT_RATIO_3D + Aspect ratio 3D + + + BAD_ORIENTED_VOLUME + Bad oriented volume + + + BELONG_TO_CYLINDER + Belong to Cylinder + + + BELONG_TO_GENSURFACE + Belong to Surface + + + BELONG_TO_GEOM + Belong to Geom + + + BELONG_TO_PLANE + Belong to Plane + + + BINARY + Binary + + + CLEAR + Clear + + + COMPARE + Compare + + + COPLANAR_FACES + Coplanar faces + + + COPY_FROM + Copy from... + + + CRITERION + Criterion + + + EDGES + Edges + + + ENTITY_TYPE + Entity type + + + EQUAL_TO + Equal to + + + ERROR + Threshold value is not correctly specified Please enter correct value and try again - - - FACES - Faces - - - FILTER - Filter - - - FREE_BORDERS - Free borders - - - FREE_EDGES - Free edges - - - FREE_NODES - Free nodes - - - - - FREE_FACES - Free faces - - - ID - ID - - - INSERT - Insert - - - LENGTH - Length - - - LENGTH2D - Length 2D - - - LESS_THAN - Less than - - - LYING_ON_GEOM - Lying on Geom - - - MINIMUM_ANGLE - Minimum angle - - - MORE_THAN - More than - - - MULTIEDGES_ERROR - Threshold value of borders at multi-connections can not be equal 1 + + + FACES + Faces + + + FILTER + Filter + + + FREE_BORDERS + Free borders + + + FREE_EDGES + Free edges + + + FREE_NODES + Free nodes + + + FREE_FACES + Free faces + + + ID + ID + + + INSERT + Insert + + + LENGTH + Length + + + LENGTH2D + Length 2D + + + LESS_THAN + Less than + + + LYING_ON_GEOM + Lying on Geom + + + MAX_ELEMENT_LENGTH_2D + Element Diameter 2D + + + MAX_ELEMENT_LENGTH_3D + Element Diameter 3D + + + MINIMUM_ANGLE + Minimum angle + + + MORE_THAN + More than + + + MULTIEDGES_ERROR + Threshold value of borders at multi-connections can not be equal 1 Please enter correct value and try again - - - GROUPCOLOR_ERROR - Color of group can not be undefied + + + GROUPCOLOR_ERROR + Color of group can not be undefied Please enter correct value and try again - - - MULTI_BORDERS - Borders at multi-connections - - - NODES - Nodes - - - NOT - Not - - - OR - Or - - - RANGE_OF_IDS - Range of IDs - - - REMOVE - Remove - - - SKEW - Skew - - - TAPER - Taper - - - THRESHOLD_VALUE - Threshold value - - - UNARY - Unary - - - VOLUMES - Volumes - - - VOLUME_3D - Volume - - - WARPING - Warping - - - LINEAR - Linear - - - GROUP_COLOR - Color of Group - - - ELEMENTS - Elements - - - GEOM_TYPE - Geometry type - - - GEOM_TYPE_0 - Point - - - GEOM_TYPE_1 - Edge - - - GEOM_TYPE_2 - Triangle - - - GEOM_TYPE_3 - Quadrangle - - - GEOM_TYPE_4 - Polygon - - - GEOM_TYPE_5 - Tetrahedron - - - GEOM_TYPE_6 - Pyramid - - - GEOM_TYPE_7 - Hexahedron - - - GEOM_TYPE_8 - Pentahedron - - - GEOM_TYPE_9 - Polyhedra - - - - SMESHGUI_GroupOpDlg - - ARGUMENTS - Arguments - - - DIFF_MESHES - Arguments of operation are not correctly specified + + + MULTI_BORDERS + Borders at multi-connections + + + NODES + Nodes + + + NOT + Not + + + OR + Or + + + RANGE_OF_IDS + Range of IDs + + + REMOVE + Remove + + + SKEW + Skew + + + TAPER + Taper + + + THRESHOLD_VALUE + Threshold value + + + UNARY + Unary + + + VOLUMES + Volumes + + + VOLUME_3D + Volume + + + WARPING + Warping + + + LINEAR + Linear + + + GROUP_COLOR + Color of Group + + + ELEMENTS + Elements + + + GEOM_TYPE + Geometry type + + + GEOM_TYPE_0 + Point + + + GEOM_TYPE_1 + Edge + + + GEOM_TYPE_2 + Triangle + + + GEOM_TYPE_3 + Quadrangle + + + GEOM_TYPE_4 + Polygon + + + GEOM_TYPE_5 + Tetrahedron + + + GEOM_TYPE_6 + Pyramid + + + GEOM_TYPE_7 + Hexahedron + + + GEOM_TYPE_8 + Pentahedron + + + GEOM_TYPE_9 + Polyhedra + + + + SMESHGUI_GroupOpDlg + + ARGUMENTS + Arguments + + + DIFF_MESHES + Arguments of operation are not correctly specified Groups correspond to a different meshes Please specify valid arguments and try again - - - DIFF_TYPES - Arguments of operation are not correctly specified + + + DIFF_TYPES + Arguments of operation are not correctly specified Groups contain elements of different types Please specify valid arguments and try again - - - EMPTY_NAME - Name of group to be created is not valid + + + EMPTY_NAME + Name of group to be created is not valid Please specify non-empty name and try again - - - INCORRECT_ARGUMENTS - Arguments of operation are not specified + + + INCORRECT_ARGUMENTS + Arguments of operation are not specified Please specify them and try again - - - NAME - Name - - - OBJECT_1 - Object 1 - - - OBJECT_2 - Object 2 - - - RESULT_NAME - Result name - - - TOOL_OBJECT - Tool object - - - UNION_OF_TWO_GROUPS - Union of two groups - - - - SMESHGUI_UnionGroupsDlg - - UNION_OF_GROUPS - Union of groups - - - - SMESHGUI_DimGroupDlg - - CREATE_GROUP_OF_UNDERLYING_ELEMS - Create group of underlying entities - + + + NAME + Name + + + OBJECT_1 + Object 1 + + + OBJECT_2 + Object 2 + + + RESULT_NAME + Result name + + + TOOL_OBJECT + Tool object + + + UNION_OF_TWO_GROUPS + Union of two groups + + + + SMESHGUI_GroupDlg + + SELECT_ALL + Select All + + + + SMESHGUI_UnionGroupsDlg + + UNION_OF_GROUPS + Union of groups + + + + SMESHGUI_DimGroupDlg + + CREATE_GROUP_OF_UNDERLYING_ELEMS + Create group of underlying entities + + + ELEMENTS_TYPE + Elements type + + + NODE + Node + + + EDGE + Edge + + + FACE + Face + + + VOLUME + Volume + + + + SMESHGUI_IntersectGroupsDlg + + INTERSECTION_OF_GROUPS + Intersection of groups + + + + SMESHGUI_CutGroupsDlg + + CUT_OF_GROUPS + Cut of groups + + + MAIN_OBJECT + Main object + + + TOOL_OBJECT + Tool object + + + + SMESHGUI_MakeNodeAtPointDlg + + AUTO_SEARCH + Find closest to destination + + + CAPTION + Move node + + + DESTINATION + Destination + + + MOVE_NODE + Move node + + + METHOD + Method + + + NODE_2MOVE + Node to move + + + NODE_2MOVE_ID + ID + + + + SMESHGUI_MakeNodeAtPointOp + + INVALID_ID + Node ID is invalid + + + INVALID_MESH + Mesh to modify not selected + + + + SMESHGUI_FindElemByPointDlg + + CAPTION + Find Element by Point + + + CREATE_NEW_METHOD + Create a node + + + MESH_PASS_THROUGH_POINT + Make a node at point + + + METHOD + Method + + + MOVE_EXISTING_METHOD + Move a node + + + NODE_2MOVE + Node to move + + + NODE_2MOVE_ID + ID + + + + SMESHGUI_MeshDlg + + CREATE_MESH + Create mesh + + + CREATE_SUBMESH + Create sub-mesh + + + DIM_0D + 0D + + + DIM_1D + 1D + + + DIM_2D + 2D + + + DIM_3D + 3D + + + EDIT_MESH_SUBMESH + Edit mesh/sub-mesh + + + GEOMETRY + Geometry + + + HYPOTHESES_SETS + Assign a set of hypotheses + + + MESH + Mesh + + + NAME + Name + + + + SMESHGUI_MeshOp + + ALGORITHM_WITHOUT_HYPOTHESIS + Algorithm is defined for %1 dimension but hypothesis is not defined + + + EDIT_SUBMESH_QUESTION + A submesh on the selected geometry already exists. + Do you want to edit this submesh? + + + SUBMESH_NOT_ALLOWED + No sense in creating a submesh ignored by global algorithm "%1" + + + GEOMETRY_OBJECT_IS_NOT_DEFINED + Geometry object is not defined +Please specify it and try again + + + GEOMETRY_OBJECT_IS_NULL + Geometry object is null + + + HYPOTHESES_AND_ALGORITHMS_ARE_NOT_DEFINED + Hypotheses and algorithms are not defined + + + HYPOTHESIS_WITHOUT_ALGORITHM + Hypothesis is defined for %1 dimension but algorithm is not defined + + + IMPORTED_MESH + Mesh is not built on geometry + + + INVALID_SUBSHAPE + Geometry object is not a subshape of the shape to mesh + + + MESH_IS_NOT_DEFINED + Mesh is not defined +Please specify it and try again + + + MESH_IS_NULL + Mesh is null + + + NAME_OF_MESH_IS_EMPTY + Name of mesh is empty +Please enter valid name and try again + + + NAME_OF_SUBMESH_IS_EMPTY + Name of submesh is empty +Please enter valid name and try again + + + THERE_IS_NO_OBJECT_FOR_EDITING + There is no object for editing. Please +select mesh or sub-mesh and try again + + + + SMESHGUI_MeshPatternDlg + + 3D_BLOCK + 3D block + + + CAPTION + Pattern Mapping + + + CREATE_POLYEDRS_NEAR_BOUNDARY + Create polyhedrons near boundary + + + CREATE_POLYGONS_NEAR_BOUNDARY + Create polygons near boundary + + + ERROR_OF_LOADING + Loading of pattern from file failed. Probably file +is corrupted or contains pattern of the other type + + + ERROR_OF_OPENING + It is impossible to open file. Please verify whether +file exists and your permission to this file + + + ERROR_OF_READING + It is impossible to load pattern +Please verify file's contents + + + ERR_READ_3D_COORD + It is impossible to load pattern +Coordinates of 3D points out of [0,1] range + + + ERR_READ_BAD_INDEX + It is impossible to load pattern +Invalid index of point detected + + + ERR_READ_BAD_KEY_POINT + It is impossible to load pattern +Key-point not on a boundary + + + ERR_READ_ELEM_POINTS + It is impossible to load pattern +invalid number of points in element + + + ERR_READ_NB_POINTS + It is impossible to load pattern +It is impossible to read number of points from file + + + ERR_READ_NO_ELEMS + It is impossible to load pattern +There are no elements in it + + + ERR_READ_NO_KEYPOINT + It is impossible to load pattern +There are no key-points in 2D one + + + ERR_READ_POINT_COORDS + It is impossible to load pattern +It is impossible to read point coordinates from file + + + ERR_READ_TOO_FEW_POINTS + It is impossible to load pattern. There are + too few points in the file for pattern loading + + + FACE + Face + + + LOAD_PATTERN + Load pattern + + + MESH_FACES + Mesh faces + + + MESH_VOLUMES + Mesh volumes + + + NEW + New... + + + NODE_1 + Node 1 + + + NODE_2 + Node 2 + + + PATTERN + Pattern + + + PATTERN_FILT + Pattern files(*.smp) + + + PATTERN_TYPE + Pattern type + + + PREVIEW + Preview + + + REFINE + Refine selected mesh elements + + + REVERSE + Reverse order of key-points + + + VERTEX + Vertex + + + VERTEX1 + Vertex 1 + + + VERTEX2 + Vertex 2 + + + + SMESHGUI_MeshTab + + ADD_HYPOTHESIS + Add. Hypothesis + + + ALGORITHM + Algorithm + + + HYPOTHESIS + Hypothesis + + + NONE + <None> + + + + SMESHGUI_MultiEditDlg + + ADD + Add + + + FILTER + Filter + + + REMOVE + Remove + + + SELECT_FROM + Select from + + + SORT_LIST + Sort list + + + SPLIT_JOIN_CRITERION + Criterion + + + TO_ALL + Apply to all + + + USE_DIAGONAL_1_3 + Use diagonal 1-3 + + + USE_DIAGONAL_2_4 + Use diagonal 2-4 + + + USE_NUMERIC_FUNC + Use numeric functor + + + + SMESHGUI_CuttingIntoTetraDlg + + CAPTION + Splitting volumes into tetrahedra + + + SPLIT_METHOD + Split hexahedron + + + SPLIT_HEX_TO_5_TETRA + Into 5 tetrahedra + + + SPLIT_HEX_TO_6_TETRA + Into 6 tetrahedra + + + SPLIT_HEX_TO_24_TETRA + Into 24 tetrahedra + + + + SMESHGUI_PrecisionDlg + + CAPTION + Precision for mesh quality controls + + + NOT_USE + Do not use + + + PRECISION + Number of digits after point + + + + SMESHGUI_RevolutionDlg + + ANGLE_BY_STEP + Angle by Step + + + PREVIEW + Preview + + + REVOLUTION_1D + Revolution of 1D elements + + + REVOLUTION_2D + Revolution of 2D elements + + + REVOLUTION_AROUND_AXIS + Revolution around an axis + + + TOTAL_ANGLE + Total Angle + + + MEN_POINT_SELECT + From Origin to selected Point + + + MEN_FACE_SELECT + Normal to selected Face + + + + SMESHGUI_SewingDlg + + BORDER + Border + + + BORDER_1 + Border 1 + + + BORDER_2 + Border 2 + + + CREATE_POLYEDRS_NEAR_BOUNDARY + Replace affected volumes by polyedres + + + CREATE_POLYGONS_INSTEAD_SPLITTING + Create polygons instead of splitting + + + ERROR_1 + Free Border1 not found by the selected nodes + + + ERROR_2 + Free Border2 not found by the selected nodes + + + ERROR_3 + Free Border1 and Border2 not found by the selected nodes + + + ERROR_4 + No path from the first side node to the last side node have been found + + + ERROR_5 + Not allowed to splite volumes on the side! + + + ERROR_6 + Different number of elements selected on the sides + + + ERROR_7 + Element sets are topologically different or given nodes are inconvenient + + + ERROR_8 + Nodes on the side 1 are either not linked or not laying on the element set boundary + + + ERROR_9 + Nodes on the side 2 are either not linked or not laying on the element set boundary + + + FIRST_NODE_ID + First Node ID + + + LAST_NODE_ID + Last Node ID + + + MERGE_EQUAL_ELEMENTS + Merge equal elements + + + NODE1_TO_MERGE + Node 1 To Merge + + + NODE2_TO_MERGE + Node 2 To Merge + + + SECOND_NODE_ID + Second Node ID + + + SEW_BORDER_TO_SIDE + Sew Border To Side + + + SEW_CONFORM_FREE_BORDERS + Sew Conform Free Borders + + + SEW_FREE_BORDERS + Sew Free Borders + + + SEW_SIDE_ELEMENTS + Sew Side Elements + + + SIDE + Side + + + SIDE_1 + Side 1 + + + SIDE_2 + Side 2 + + + + SMESHGUI_ShapeByMeshDlg + + CAPTION + Find geometry by mesh element + + + + SMESHGUI_SingleEditDlg + + EDGE_BETWEEN + Edge between neighboring triangles + + + + SMESHGUI_SmoothingDlg + + CENTROIDAL + Centroidal + + + FIXED_NODES_IDS + Fixed nodes ids + + + IS_PARAMETRIC + in parametric space + + + ITERATION_LIMIT + Iteration limit + + + LAPLACIAN + Laplacian + + + MAX_ASPECT_RATIO + Max. aspect ratio + + + METHOD + Method + + + + SMESHGUI_TrianglesInversionDlg + + CAPTION + Diagonal inversion + + + + SMESHGUI_UnionOfTrianglesDlg + + CAPTION + Union of triangles + + + MAXIMUM_ANGLE + Maximum bending angle + + + + SMESHGUI_UnionOfTwoTrianglesDlg + + CAPTION + Union of two triangles + + + + SMESHGUI_WhatIsDlg + + ENTITY_TYPE + Element type + + + GRAVITY_CENTER + Gravity center + + + CONNECTED_ELEMENTS + Connected With Elements + + + + SMESHGUI_FileInfoDlg + + CAPTION + File information + + + FILE_NAME + File name + + + FILE_SIZE + File size (bytes) + + + MED_VERSION + MED version + + + + SMESHGUI_GroupOnShapeDlg + + SMESH_CREATE_GROUP_FROM_GEOM + Create Groups from Geometry + + + + SMESHGUI_MeshOrderDlg + + SMESH_MESHORDER_TITLE + Order of submesh in meshing process + + + + SMESHGUI_MeshOrderOp + + SMESH_NO_CONCURENT_MESH + No concurent submeshes detected + + + + SMESHGUI_ClippingDlg + + CLIP_PLANES + Clipping planes + + + MESHES_SUBMESHES_GROUPS + Meshes, sub-meshes and groups + + + SELECT_ALL + Select all + + + ROTATION_AROUND_X_Y2Z + Rotation around X (Y to Z): + + + ROTATION_AROUND_Y_X2Z + Rotation around Y (X to Z): + + + ROTATION_AROUND_Z_Y2X + Rotation around Z (Y to X): + + + ROTATION_AROUND_X_Z2Y + Rotation around X (Z to Y): + + + ROTATION_AROUND_Y_Z2X + Rotation around Y (Z to X): + + + ROTATION_AROUND_Z_X2Y + Rotation around Z (X to Y): + + + SHOW_PREVIEW + Show preview + + + AUTO_APPLY + Auto Apply + + + ALONG_XY + || X-Y + + + ALONG_YZ + || Y-Z + + + ALONG_ZX + || Z-X + + + PLANE_NUM + Plane# %1 + + + NO_PLANES + No planes + + + + SMESHGUI_DuplicateNodesDlg + + DUPLICATION_MODE + Duplication mode + + + DUPLICATION_WITHOUT_ELEMS + Without duplication of border elements + + + GROUP_NODES_TO_DUPLICATE + Group of nodes to duplicate + + + GROUP_NODES_TO_REPLACE + Group of elements to replace nodes with new ones + + + DUPLICATION_WITH_ELEMS + With duplication of border elements + + + GROUP_ELEMS_TO_DUPLICATE + Group of elements to duplicate + + + GROUP_NODES_NOT_DUPLICATE + Group of nodes not to duplicate + + + GROUP_ELEMS_TO_REPLACE + Group of elements to replace nodes with new ones + + + CONSTRUCT_NEW_GROUP_NODES + Construct group with newly created nodes + + + CONSTRUCT_NEW_GROUP_ELEMENTS + Construct group with newly created elements + + + + SMESHGUI_Make2DFrom3DDlg + + CAPTION + Create boundary elements + + + MESH + Mesh, submesh or group + + + MODE + Mode + + + 2D_FROM_3D + 2D from 3D + + + 1D_FROM_3D + 1D from 3D + + + 1D_FROM_2D + 1D from 2D + + + TARGET + Target + + + THIS_MESH + This mesh + + + NEW_MESH + New mesh + + + COPY_SRC + Copy source mesh + + + MISSING_ONLY + Copy missing elements only + + + CREATE_GROUP + Create group + + + + SMESHGUI_Make2DFrom3DOp + + SMESH_ERR_NO_INPUT_MESH + Source mesh, sub-mesh or group is not specified + + + SMESH_ERR_NO_3D_ELEMENTS + The source object does not contain 3D elements + + + SMESH_ERR_NO_2D_ELEMENTS + The source object does not contain 2D elements + + + SMESH_ERR_MESH_NAME_NOT_SPECIFIED + New mesh name is not specified + + + SMESH_ERR_GRP_NAME_NOT_SPECIFIED + Group name is not specified + + + + SMESHGUI_MeshInfo + + NAME_LAB + Name: + + + OBJECT_LAB + Object: + + + NODES_LAB + Nodes: + + + ELEMENTS_LAB + Elements: + + + TOTAL_LAB + Total + + + LINEAR_LAB + Linear + + + QUADRATIC_LAB + Quadratic + + + 0D_LAB + 0D: + + + 1D_LAB + 1D (edges): + + + 2D_LAB + 2D (faces): + + + TRIANGLES_LAB + Triangles: + + + QUADRANGLES_LAB + Quadrandgles: + + + POLYGONS_LAB + Polygons: + + + 3D_LAB + 3D (volumes): + + + TETRAHEDRONS_LAB + Tetrahedrons: + + + HEXAHEDONRS_LAB + Hexahedrons: + + + PYRAMIDS_LAB + Pyramids: + + + PRISMS_LAB + Prisms: + + + POLYHEDRONS_LAB + Polyhedrons: + + + OBJECT_MESH + Mesh + + + OBJECT_SUBMESH + Sub-mesh + + + OBJECT_GROUP + Group + + + OBJECT_GROUP_NODES + Group of nodes + + + OBJECT_GROUP_EDGES + Group of edges + + + OBJECT_GROUP_FACES + Group of faces + + + OBJECT_GROUP_VOLUMES + Group of volumes + + + OBJECT_GROUP_0DELEMS + Group of 0D elements + + + + SMESHGUI_MeshInfoDlg + + MESH_INFO + Mesh Information + + + BASE_INFO + Base Info + + + ELEM_INFO + Element Info + + + NODE_MODE + Node + + + ELEM_MODE + Element + + + + SMESHGUI_ElemInfo + + COORDINATES + COORDINATES + + + CONNECTIVITY + CONNECTIVITY + + + GRAVITY_CENTER + GRAVITY CENTER + + + NODE + NODE + + + 0D_ELEMENT + 0D ELEMENT + + + 0D_ELEMENTS + 0D ELEMENTS + + + EDGE + EDGE + + + EDGES + EDGES + + + FACE + FACE + + + FACES + FACES + + + VOLUME + VOLUME + + + VOLUMES + VOLUMES + + + FREE_NODE + Free node (no connectivity) + + + TYPE + TYPE + + + TRIANGLE + Triangle + - ELEMENTS_TYPE - Elements type - + QUADRANGLE + Quadrangle + + + POLYGON + Polygon + + + TETRAHEDRON + Tetrahedron + + + HEXAHEDRON + Hexahedron + + + PYRAMID + Pyramid + + + PRISM + Prism + + + POLYHEDRON + Polyhedron + + + QUADRATIC + QUADRATIC + + + YES + Yes + + + NO + No + + + GRAVITY_CENTER + GRAVITY CENTER + + + PROPERTY + Property + + + VALUE + Value + + + + SMESHGUI_MinDistance + + FIRST_TARGET + First target + + + SECOND_TARGET + Second target + NODE Node - + - EDGE - Edge + ELEMENT + Element - FACE - Face + OBJECT + Object - VOLUME - Volume + ORIGIN + Origin - - - SMESHGUI_IntersectGroupsDlg - - INTERSECTION_OF_GROUPS - Intersection of groups - - - - SMESHGUI_CutGroupsDlg - - CUT_OF_GROUPS - Cut of groups - - - MAIN_OBJECT - Main object - - - TOOL_OBJECT - Tool object - - - - SMESHGUI_MakeNodeAtPointDlg - - AUTO_SEARCH - Automatic search - - - CAPTION - Mesh to pass through a point - - - CREATE_NEW_METHOD - Create a node - - - MESH_PASS_THROUGH_POINT - Make a node at point - - - METHOD - Method - - - MOVE_EXISTING_METHOD - Move a node - - - NODE_2MOVE - Node to move - - - NODE_2MOVE_ID - ID - - - - SMESHGUI_MakeNodeAtPointOp - - INVALID_ID - Node ID is invalid - - - INVALID_MESH - Mesh to modify not selected - - - - SMESHGUI_FindElemByPointDlg - - CAPTION - Find Element by Point - - - CREATE_NEW_METHOD - Create a node - - - MESH_PASS_THROUGH_POINT - Make a node at point - - - METHOD - Method - - - MOVE_EXISTING_METHOD - Move a node - - - NODE_2MOVE - Node to move - - - NODE_2MOVE_ID - ID - - - - SMESHGUI_MeshDlg - - CREATE_MESH - Create mesh - - - CREATE_SUBMESH - Create sub-mesh - - - DIM_0D - 0D - - - DIM_1D - 1D - - - DIM_2D - 2D - - - DIM_3D - 3D - - - EDIT_MESH_SUBMESH - Edit mesh/sub-mesh - - - GEOMETRY - Geometry - - - HYPOTHESES_SETS - Assign a set of hypotheses - - - MESH - Mesh - - - NAME - Name - - - - SMESHGUI_MeshOp - - ALGORITHM_WITHOUT_HYPOTHESIS - Algorithm is defined for %1 dimension but hypothesis is not defined - - - EDIT_SUBMESH_QUESTION - A submesh on the selected geometry already exists. - Do you want to edit this submesh? - - - SUBMESH_NOT_ALLOWED - No sense in creating a submesh ignored by global algorithm "%1" - - - GEOMETRY_OBJECT_IS_NOT_DEFINED - Geometry object is not defined -Please specify it and try again - - - GEOMETRY_OBJECT_IS_NULL - Geometry object is null - - - HYPOTHESES_AND_ALGORITHMS_ARE_NOT_DEFINED - Hypotheses and algorithms are not defined - - - HYPOTHESIS_WITHOUT_ALGORITHM - Hypothesis is defined for %1 dimension but algorithm is not defined - - - IMPORTED_MESH - Mesh is not built on geometry - - - INVALID_SUBSHAPE - Geometry object is not a subshape of the shape to mesh - - - MESH_IS_NOT_DEFINED - Mesh is not defined -Please specify it and try again - - - MESH_IS_NULL - Mesh is null - - - NAME_OF_MESH_IS_EMPTY - Name of mesh is empty -Please enter valid name and try again - - - NAME_OF_SUBMESH_IS_EMPTY - Name of submesh is empty -Please enter valid name and try again - - - THERE_IS_NO_OBJECT_FOR_EDITING - There is no object for editing. Please -select mesh or sub-mesh and try again - - - - SMESHGUI_MeshPatternDlg - - 3D_BLOCK - 3D block - - - CAPTION - Pattern Mapping - - - CREATE_POLYEDRS_NEAR_BOUNDARY - Create polyhedrons near boundary - - - CREATE_POLYGONS_NEAR_BOUNDARY - Create polygons near boundary - - - ERROR_OF_LOADING - Loading of pattern from file failed. Probably file -is corrupted or contains pattern of the other type - - - ERROR_OF_OPENING - It is impossible to open file. Please verify whether -file exists and your permission to this file - - - ERROR_OF_READING - It is impossible to load pattern -Please verify file's contents - - - ERR_READ_3D_COORD - It is impossible to load pattern -Coordinates of 3D points out of [0,1] range - - - ERR_READ_BAD_INDEX - It is impossible to load pattern -Invalid index of point detected - - - ERR_READ_BAD_KEY_POINT - It is impossible to load pattern -Key-point not on a boundary - - - ERR_READ_ELEM_POINTS - It is impossible to load pattern -invalid number of points in element - - - ERR_READ_NB_POINTS - It is impossible to load pattern -It is impossible to read number of points from file - - - ERR_READ_NO_ELEMS - It is impossible to load pattern -There are no elements in it - - - ERR_READ_NO_KEYPOINT - It is impossible to load pattern -There are no key-points in 2D one - - - ERR_READ_POINT_COORDS - It is impossible to load pattern -It is impossible to read point coordinates from file - - - ERR_READ_TOO_FEW_POINTS - It is impossible to load pattern. There are - too few points in the file for pattern loading - - - FACE - Face - - - LOAD_PATTERN - Load pattern - - - MESH_FACES - Mesh faces - - - MESH_VOLUMES - Mesh volumes - - - NEW - New... - - - NODE_1 - Node 1 - - - NODE_2 - Node 2 - - - PATTERN - Pattern - - - PATTERN_FILT - Pattern files(*.smp) - - - PATTERN_TYPE - Pattern type - - - PREVIEW - Preview - - - REFINE - Refine selected mesh elements - - - REVERSE - Reverse order of key-points - - - VERTEX - Vertex - - - VERTEX1 - Vertex 1 - - - VERTEX2 - Vertex 2 - - - - SMESHGUI_MeshTab - - ADD_HYPOTHESIS - Add. Hypothesis - - - ALGORITHM - Algorithm - - - HYPOTHESIS - Hypothesis - - - NONE - <None> - - - - SMESHGUI_MoveNodesDlg - - CAPTION - Move node - - - NODE_ID_IS_NOT_DEFINED - Node ID is not defined - - - - SMESHGUI_MultiEditDlg - - ADD - Add - - - FILTER - Filter - - - REMOVE - Remove - - - SELECT_FROM - Select from - - - SORT_LIST - Sort list - - - SPLIT_JOIN_CRITERION - Criterion - - - TO_ALL - Apply to all - - - USE_DIAGONAL_1_3 - Use diagonal 1-3 - - - USE_DIAGONAL_2_4 - Use diagonal 2-4 - - - USE_NUMERIC_FUNC - Use numeric functor - - - - SMESHGUI_CuttingIntoTetraDlg - - CAPTION - Splitting volumes into tetrahedra - - - SPLIT_METHOD - Split hexahedron - - - SPLIT_HEX_TO_5_TETRA - Into 5 tetrahedra - - - SPLIT_HEX_TO_6_TETRA - Into 6 tetrahedra - - - - SMESHGUI_PrecisionDlg - - CAPTION - Precision for mesh quality controls - - - NOT_USE - Do not use - - - PRECISION - Number of digits after point - - - - SMESHGUI_RevolutionDlg - - ANGLE_BY_STEP - Angle by Step - - - PREVIEW - Preview - - - REVOLUTION_1D - Revolution of 1D elements - - - REVOLUTION_2D - Revolution of 2D elements - - - REVOLUTION_AROUND_AXIS - Revolution around an axis - - - TOTAL_ANGLE - Total Angle - - - MEN_POINT_SELECT - From Origin to selected Point - - - MEN_FACE_SELECT - Normal to selected Face - - - - SMESHGUI_SewingDlg - - BORDER - Border - - - BORDER_1 - Border 1 - - - BORDER_2 - Border 2 - - - CREATE_POLYEDRS_NEAR_BOUNDARY - Replace affected volumes by polyedres - - - CREATE_POLYGONS_INSTEAD_SPLITTING - Create polygons instead of splitting - - - ERROR_1 - Free Border1 not found by the selected nodes - - - ERROR_2 - Free Border2 not found by the selected nodes - - - ERROR_3 - Free Border1 and Border2 not found by the selected nodes - - - ERROR_4 - No path from the first side node to the last side node have been found - - - ERROR_5 - Not allowed to splite volumes on the side! - - - ERROR_6 - Different number of elements selected on the sides - - - ERROR_7 - Element sets are topologically different or given nodes are inconvenient - - - ERROR_8 - Nodes on the side 1 are either not linked or not laying on the element set boundary - - - ERROR_9 - Nodes on the side 2 are either not linked or not laying on the element set boundary - - - FIRST_NODE_ID - First Node ID - - - LAST_NODE_ID - Last Node ID - - - MERGE_EQUAL_ELEMENTS - Merge equal elements - - - - NODE1_TO_MERGE - Node 1 To Merge - - - NODE2_TO_MERGE - Node 2 To Merge - - - SECOND_NODE_ID - Second Node ID - - - SEW_BORDER_TO_SIDE - Sew Border To Side - - - SEW_CONFORM_FREE_BORDERS - Sew Conform Free Borders - - - SEW_FREE_BORDERS - Sew Free Borders - - - SEW_SIDE_ELEMENTS - Sew Side Elements - - - SIDE - Side - - - SIDE_1 - Side 1 - - - SIDE_2 - Side 2 - - - - SMESHGUI_ShapeByMeshDlg - - CAPTION - Find geometry by mesh element - - - - SMESHGUI_SingleEditDlg - - EDGE_BETWEEN - Edge between neighboring triangles - - - - SMESHGUI_SmoothingDlg - - CENTROIDAL - Centroidal - - - FIXED_NODES_IDS - Fixed nodes ids - - - IS_PARAMETRIC - in parametric space - - - ITERATION_LIMIT - Iteration limit - - - LAPLACIAN - Laplacian - - - MAX_ASPECT_RATIO - Max. aspect ratio - - - METHOD - Method - - - - SMESHGUI_TrianglesInversionDlg - - CAPTION - Diagonal inversion - - - - SMESHGUI_UnionOfTrianglesDlg - - CAPTION - Union of triangles - - - MAXIMUM_ANGLE - Maximum bending angle - - - - SMESHGUI_UnionOfTwoTrianglesDlg - - CAPTION - Union of two triangles - - - - SMESHGUI_WhatIsDlg - - ENTITY_TYPE - Element type - - - GRAVITY_CENTER - Gravity center - - - CONNECTED_ELEMENTS - Connected With Elements - - - - SMESHGUI_FileInfoDlg - - CAPTION - File information - - - FILE_NAME - File name - - - FILE_SIZE - File size (bytes) - - - MED_VERSION - MED version - - - - SMESHGUI_GroupOnShapeDlg - - SMESH_CREATE_GROUP_FROM_GEOM - Create Groups from Geometry - - - - SMESHGUI_MeshOrderDlg - - SMESH_MESHORDER_TITLE - Order of submesh in meshing process - - - - SMESHGUI_MeshOrderOp - - SMESH_NO_CONCURENT_MESH - No concurent submeshes detected - - - - SMESHGUI_ClippingDlg - - CLIP_PLANES - Clipping planes - - - ROTATION_AROUND_X_Y2Z - Rotation around X (Y to Z): - - - ROTATION_AROUND_Y_X2Z - Rotation around Y (X to Z): - - - ROTATION_AROUND_Z_Y2X - Rotation around Z (Y to X): - - - ROTATION_AROUND_X_Z2Y - Rotation around X (Z to Y): - - - ROTATION_AROUND_Y_Z2X - Rotation around Y (Z to X): - - - ROTATION_AROUND_Z_X2Y - Rotation around Z (X to Y): - - - SHOW_PREVIEW - Show preview - - - AUTO_APPLY - Auto Apply - - - ALONG_XY - || X-Y - - - ALONG_YZ - || Y-Z - - - ALONG_ZX - || Z-X - - - PLANE_NUM - Plane# %1 - - - NO_PLANES - No planes - - + + COMPUTE + Compute + + + RESULT + Distance between targets + + + DISTANCE + Distance + + + + SMESHGUI_MeasureDlg + + MEASUREMENTS + Measurements + + + MIN_DIST + Minimum Distance + + + BND_BOX + Bounding Box + + + + SMESHGUI_BoundingBox + + SOURCE + Source + + + OBJECTS + Objects + + + NODES + Nodes + + + ELEMENTS + Elements + + + COMPUTE + Compute + + + RESULT + Bounding Box + + + SELECTED_NB_OBJ + %1 %2 selected + + + NB_NODES + nodes + + + NB_ELEMENTS + elements + + diff --git a/src/SMESHGUI/SMESH_msg_fr.ts b/src/SMESHGUI/SMESH_msg_fr.ts new file mode 100755 index 000000000..955e9396b --- /dev/null +++ b/src/SMESHGUI/SMESH_msg_fr.ts @@ -0,0 +1,5346 @@ + + + + + @default + + AREA_ELEMENTS + Aire + + + ASPECTRATIO_3D_ELEMENTS + Rapport de forme 3D + + + ASPECTRATIO_ELEMENTS + Rapport de forme + + + COL_ALGO_HEADER + Algorithme + + + COL_ERROR_HEADER + Erreur + + + COL_SHAPE_HEADER + SousObjet + + + COMPERR_ALGO_FAILED + L'algorithme n'a pas abouti + + + COMPERR_BAD_INPUT_MESH + Le maillage d'entrée est invalide + + + COMPERR_BAD_SHAPE + Géométrie inattendue + + + COMPERR_EXCEPTION + Exception inconnue + + + COMPERR_MEMORY_PB + Problème d'affectation de la mémoire + + + COMPERR_OCC_EXCEPTION + Exception OCC + + + COMPERR_OK + Pas d'erreur + + + COMPERR_SLM_EXCEPTION + Exception SALOME + + + COMPERR_STD_EXCEPTION + std::exception + + + SMESH_GEOM + Géométrie + + + DIRECT_GEOM_SELECTION + Sélection directe de la géométrie + + + ELEMENT_ID + ID de l'élément + + + FREE_BORDERS + Frontières libres + + + GEOMETRY_NAME + Nom de la géométrie + + + GEOM_BY_MESH_ELEM_SELECTION + Trouver la géométrie en choisissant l'élément de maillage + + + GLOBAL_ALGO + Global + + + INF_SELECT_OBJECT + Choisir un objet + + + LENGTH2D_EDGES + Longueur 2D + + + LENGTH_EDGES + Longueur + + + LOCAL_ALGO + Local + + + MEN_ADD + Ajouter + + + MEN_ADV_INFO + Informations avancées du maillage + + + MEN_ALL + Tous + + + MEN_AREA + Aire + + + MEN_ASPECT + Rapport de forme + + + MEN_ASPECT_3D + Rapport de forme 3D + + + MEN_AUTO_COLOR + Couleur automatique + + + MEN_AUTO_UPD + Mise à jour automatique + + + MEN_BUILD_COMPOUND + Construire un assemblage + + + MEN_CLIP + Plan de coupe + + + MEN_COLORS + Couleurs / Taille + + + MEN_COMPUTE + Calculer + + + MEN_PRECOMPUTE + Prévisualiser + + + MEN_EVALUATE + Evaluer + + + MEN_CONNECTION + Frontières sur connections multiples + + + MEN_CONNECTION_2D + Frontières sur connections multiples 2D + + + MEN_CONSTRUCT_GROUP + Construire un groupe + + + MEN_CONV_TO_QUAD + Convertir vers/de quadratique + + + MEN_2D_FROM_3D + Créer les éléments de frontière + + + MEN_MESH_ORDER + Changer la priorité des sous-maillages + + + MEN_CREATE_GROUP + Créer un groupe + + + MEN_CREATE_GEO_GROUP + Créer les groupes à partir de la géométrie + + + MEN_CREATE_MESH + Créer un maillage + + + MEN_CREATE_SUBMESH + Créer un sous-maillage + + + MEN_CTRL + Contrôles + + + MEN_CUT + Découpe des quadrangles + + + MEN_CUT_GROUP + Découpe des groupes + + + MEN_DAT + Fichier DAT + + + MEN_DELETE + Supprimer + + + MEN_DEL_GROUP + Supprimer les groupes + + + MEN_FACE_ORIENTATION + Orientation des faces + + + MEN_DISABLE_AUTO_COLOR + Désactiver la couleur automatique + + + MEN_DISPLAY_ONLY + Afficher uniquement + + + MEN_DISPMODE + Mode de visualisation + + + MEN_DISP_ENT + Montrer l'entité + + + MEN_ELEM0D + Elément 0D + + + MEN_ELEMS0D + Eléments 0D + + + MEN_EDGE + Arête + + + MEN_EDGES + Arêtes + + + MEN_EDIT + Edition + + + MEN_EDIT_GROUP + Editer un groupe + + + MEN_EDIT_GEOMGROUP_AS_GROUP + Editer un groupe en tant qu'autonome + + + MEN_EDIT_HYPO + Editer une hypothèse + + + MEN_EDIT_MESHSUBMESH + Editer un maillage/sous-maillage + + + MEN_EXPORT + Exporter + + + MEN_EXPORT_DAT + Exporter au format DAT + + + MEN_EXPORT_MED + Exporter au format MED + + + MEN_EXPORT_SAUV + Exporter au format SAUV (ASCII) + + + MEN_EXPORT_STL + Exporter au format STL + + + MEN_EXPORT_UNV + Exporter au format UNV + + + MEN_EXTRUSION + Extrusion + + + MEN_EXTRUSION_ALONG + Extrusion suivant un chemin + + + MEN_FACES + Faces + + + MEN_FILE + Fichier + + + MEN_FIND_ELEM + Trouver un élément par un point + + + TOP_FIND_ELEM + Trouver un élément par un point + + + STB_FIND_ELEM + Trouver un élément par un point + + + MEN_FREE_BORDER + Frontières libres + + + MEN_FREE_EDGE + Arêtes libres + + + MEN_FREE_NODE + Nœuds libres + + + MEN_FREE_FACES + Faces libres + + + MEN_GLOBAL_HYPO + Hypothèse globale + + + MEN_HEXA + Hexaèdre + + + MEN_HIDE + Cacher + + + MEN_HYPO + Hypothèses + + + MEN_IMPORT + Importer + + + MEN_INT_GROUP + Intersection des groupes + + + MEN_INV + Inversion de diagonale + + + MEN_LENGTH + Longueur + + + MEN_LENGTH_2D + Longueur 2D + + + MEN_MAP + Projection de motif + + + MEN_MED + Fichier MED + + + MEN_SAUV + Fichier SAUV (ASCII) + + + MEN_MERGE + Fusionner les nœuds + + + MEN_MERGE_ELEMENTS + Fusionner les éléments + + + MEN_MESH + Maillage + + + MEN_MESH_THROU_POINT + Déplacer un nœud + + + MEN_MIN_ANG + Angle minimal + + + MEN_MODIFY + Modification + + + MEN_MOVE + Déplacer un nœud + + + MEN_NODE + Nœud + + + MEN_NODES + Nœuds + + + MEN_NUM + Numérotation + + + MEN_NUM_ELEMENTS + Montrer les n° des éléments + + + MEN_NUM_NODES + Montrer les n° des nœuds + + + MEN_ORIENT + Orientation + + + MEN_POLYGON + Polygone + + + MEN_POLYHEDRON + Polyèdre + + + MEN_PRECISION + Précision + + + MEN_PREF + Préférences + + + MEN_QUAD + Quadrangle + + + MEN_QUADRATIC_EDGE + Arête quadratique + + + MEN_QUADRATIC_HEXAHEDRON + Hexaèdre quadratique + + + MEN_QUADRATIC_PENTAHEDRON + Pentaèdre quadratique + + + MEN_QUADRATIC_PYRAMID + Pyramide quadratique + + + MEN_QUADRATIC_QUADRANGLE + Quadrangle quadratique + + + MEN_QUADRATIC_TETRAHEDRON + Tetraèdre quadratique + + + MEN_QUADRATIC_TRIANGLE + Triangle quadratique + + + MEN_QUALITY + Contrôles de qualité + + + MEN_REMOVE + Supprimer + + + MEN_REMOVE_ELEMENTS + Eléments + + + MEN_REMOVE_NODES + Nœuds + + + MEN_REMOVE_ORPHAN_NODES + Nœuds orphelins + + + MEN_RENAME + Renommer + + + MEN_RENUM + Renuméroter + + + MEN_RENUM_ELEMENTS + Eléments + + + MEN_RENUM_NODES + Nœuds + + + MEN_RESET + Restaurer + + + MEN_REVOLUTION + Révolution + + + MEN_ROT + Rotation + + + MEN_SCALAR_BAR + Barre scalaire + + + MEN_SCALAR_BAR_PROP + Propriétés de la barre scalaire + + + MEN_SELECTION + Sélection + + + MEN_SEL_FILTER_LIB + Librairie des filtres de sélection + + + MEN_SEW + Couture + + + MEN_SHADE + Ombrage + + + MEN_QUADRATIC_REPRESENT + Quadratique 2D + + + MEN_LINE_REPRESENTATION + Lignes + + + MEN_ARC_REPRESENTATION + Arcs + + + MEN_SHOW + Visualiser + + + MEN_SHRINK + Contraction + + + MEN_SKEW + Inclinaison d'angle + + + MEN_SMOOTH + Lissage + + + MEN_STD_INFO + Informations du maillage + + + MEN_STL + Fichier STL + + + MEN_SYM + Symétrie + + + MEN_TAPER + Cône + + + MEN_TETRA + Tétraèdre + + + MEN_TOOLS + Outils + + + MEN_TRANS + Translation + + + MEN_SCALE + Transformation d'échelle + + + MEN_DUPLICATE_NODES + Dupliquer les nœuds + + + MEN_TRANSF + Transformation + + + MEN_TRANSP + Transparence + + + MEN_TRIANGLE + Triangle + + + MEN_UNASSIGN + Désassocier + + + MEN_UNION + Union des triangles + + + MEN_UNION2 + Union de deux triangles + + + MEN_UNV + Fichier UNV + + + MEN_UN_GROUP + Union des groupes + + + MEN_UNDERLYING_ELEMS + Groupe des entités sous-jacentes + + + MEN_UPDATE + Mettre à jour + + + MEN_VIEW + Affichage + + + MEN_VOLUMES + Volumes + + + MEN_VOLUME_3D + Volume + + + MEN_WARP + Angle de déformation + + + MEN_WHAT_IS + Information sur un élément de maillage + + + MEN_WIRE + Contours + + + MEN_SPLIT_TO_TETRA + Explosion en tétraèdres + + + TOP_SPLIT_TO_TETRA + Eclater en tétraèdres + + + STB_SPLIT_TO_TETRA + Eclater en tétraèdres + + + MESHERS_FILE_CANT_OPEN + Impossible d'ouvrir le fichier de ressource + + + MESHERS_FILE_CHECK_VARIABLE + Vérifier la variable d'environnement SMESH_MeshersList + + + MESHERS_FILE_NO_VARIABLE + La variable d'environnement SMESH_MeshersList n'est pas définie + + + MESH_IS_NOT_SELECTED + Il n'y a pas de maillage sélectionné. +Choisissez un maillage et essayez de nouveau + + + MESH_NODE + Nœud + + + MESH_NODE_TITLE + Ajouter un nœud + + + MINIMUMANGLE_ELEMENTS + Angle minimal + + + MULTI2D_BORDERS + Frontières sur multi-connections 2D + + + MULTI_BORDERS + Frontières sur multi-connections + + + GROUP_NAME_IS_EMPTY + Le nom du groupe n'est pas indiqué. +Indiquez le nom d'un nouveau groupe à créer ou choisissez un groupe existant. + + + MESH_STANDALONE_GRP_CHOSEN + Un groupe lié à la géométrie est choisi: %1. +Voulez-vous le convertir en un groupe autonome ? + + + NODE_ID + ID du nœud + + + NON_SMESH_OBJECTS_SELECTED + Certains objets sélectionnés n'appartiennent pas au composant %1. + + + PREVIEW + Prévisualiser + + + SKEW_ELEMENTS + Inclinaison d'angle + + + SMESHGUI_INVALID_PARAMETERS + Les paramètres spécifiés ne sont pas corrects. +Merci de les corriger, puis essayez de nouveau + + + SMESH_ADD_ALGORITHM + Algorithmes + + + SMESH_ADD_ALGORITHM_TITLE + Attribution des algorithmes + + + SMESH_ADD_ELEM0D + Ajouter un élément 0D + + + SMESH_ADD_ELEM0D_TITLE + Ajouter un élément 0D + + + SMESH_ADD_EDGE + Ajouter une arête + + + SMESH_ADD_EDGE_TITLE + Ajouter une arête + + + SMESH_ADD_HEXAS + Ajouter un hexaèdre + + + SMESH_ADD_HEXAS_TITLE + Ajouter un hexahèdre + + + SMESH_ADD_HYPOTHESIS + Hypothèse + + + SMESH_ADD_HYPOTHESIS_TITLE + Attrbution d'une hypothèse + + + SMESH_ADD_HYP_WRN + "%1" est attribué, mais: + + + + SMESH_ADD_POLYGON + Ajouter un polygone + + + SMESH_ADD_POLYGON_TITLE + Ajouter un polygone + + + SMESH_ADD_QUADRANGLE + Ajouter un quadrangle + + + SMESH_ADD_QUADRANGLE_TITLE + Ajouter un quadrangle + + + SMESH_ADD_QUADRATIC_EDGE_TITLE + Ajouter une arête quadratique + + + SMESH_ADD_QUADRATIC_HEXAHEDRON_TITLE + Ajouter un hexaèdre quadratique + + + SMESH_ADD_QUADRATIC_PENTAHEDRON_TITLE + Ajouter un pentaèdre quadratique + + + SMESH_ADD_QUADRATIC_PYRAMID_TITLE + Ajouter une pyramide quadratique + + + SMESH_ADD_QUADRATIC_QUADRANGLE_TITLE + Ajouter un quadrangle quadratique + + + SMESH_ADD_QUADRATIC_TETRAHEDRON_TITLE + Ajouter un tétraèdre quadratique + + + SMESH_ADD_QUADRATIC_TRIANGLE_TITLE + Ajouter un triangle quadratique + + + SMESH_ADD_SUBMESH + Construction d'un sous-maillage + + + SMESH_ADD_TETRAS + Ajouter un tétraèdre + + + SMESH_ADD_TETRAS_TITLE + Ajouter un tétraèdre + + + SMESH_ADD_TO_GROUP + Ajouter à un groupe + + + SMESH_ADD_TRIANGLE + Ajouter un triangle + + + SMESH_ADD_TRIANGLE_TITLE + Ajouter un triangle + + + SMESH_ANGLE + Angle + + + SMESH_ARGUMENTS + Arguments + + + SMESH_AUTO_GROUPS + Créer les groupes automatiquement + + + SMESH_AVAILABLE + Disponible + + + SMESH_AVAILABLE_ALGORITHMS + Algorithmes disponibles + + + SMESH_AVAILABLE_HYPOTHESES + Hypothèses disponibles + + + SMESH_AXIS + Axe + + + SMESH_BAD_SELECTION + Pas de sélection valide + + + SMESH_BAD_MESH_SELECTION + La sélection du maillage n'est pas valide + + + SMESH_BOUNDARYEDGES + Arêtes frontières + + + SMESH_BUILD_COMPOUND_TITLE + Créer un assemblage + + + SMESH_BUT_ADD + A&jouter + + + SMESH_BUT_APPLY + A&ppliquer + + + SMESH_BUT_CANCEL + A&nnuler + + + SMESH_BUT_CLOSE + &Fermer + + + SMESH_BUT_CREATE + &Créer + + + SMESH_BUT_DELETE + Eff&acer + + + SMESH_BUT_FILTER + Définir les fil&tres + + + SMESH_BUT_HELP + Ai&de + + + SMESH_BUT_NEW + Nou&veau + + + SMESH_BUT_NO + &Non + + + SMESH_BUT_OK + &Ok + + + SMESH_BUT_OVERWRITE + Réécr&ire + + + SMESH_BUT_APPLY_AND_CLOSE + App&liquer et fermer + + + SMESH_BUT_REMOVE + S&upprimer + + + SMESH_BUT_SORT + &Trier la liste + + + SMESH_BUT_YES + &Oui + + + SMESH_CANT_ADD_HYP + Impossible d'attribuer "%1": + + + + SMESH_CANT_RM_HYP + Impossible de désassigner "%1": + + + + SMESH_CHECK_COLOR + Couleur + + + SMESH_CLIPPING_FROM + De <--- + + + SMESH_CLIPPING_INTO + ---> En + + + SMESH_CLIPPING_TITLE + Changer le plan de coupe + + + SMESH_COMPUTE_SUCCEED + Le calcul du maillage a réussi + + + SMESH_EVALUATE_SUCCEED + L'évaluation du maillage a réussi + + + SMESH_CONTENT + Contenu + + + SMESH_CONTINUE_MESH_VISUALIZATION + La système semble manquer de mémoire pour visualiser le maillage, +ce qui peut faire planter l'application. Voulez-vous continuer la visualisation ? + + + SMESH_COORDINATES + Coordonnées + + + SMESH_COPY_ELEMENTS + Copier les éléments + + + SMESH_COPY_GROUPS + Copier les groupes + + + SMESH_CREATE_ALGORITHMS + Créer les algorithmes + + + SMESH_CREATE_COPY + Créer une copie + + + SMESH_CREATE_GROUP_TITLE + Créer un groupe + + + SMESH_CREATE_GEO_GROUP + Créer les groupes liés à la géométrie + + + SMESH_CREATE_HYPOTHESES + Créer une hypothèse + + + SMESH_CREATE_MESH + Créer un nouveau maillage + + + SMESH_CREATE_POLYHEDRAL_VOLUME_TITLE + Créer un volume polyèdrique + + + SMESH_DIAGONAL + Inversion de diagonale + + + SMESH_DIAGONAL_INVERSION_TITLE + Inversion de diagonale + + + SMESH_DISTANCE + Distance + + + SMESH_DRS_1 + Le fichier MED contient pas de maillage avec ce nom + + + SMESH_DRS_2 + Le fichier MED contient des rangées de nombre d'éléments superposées, donc les nombres de ce fichier ne sont pas pris en compte + + + SMESH_DRS_3 + Quelques éléments ont été omis à cause du fichier de données incorrect + + + SMESH_DRS_4 + Le fichier n'est pas correct, des données sont manquantes + + + SMESH_DRS_EMPTY + Le fichier est vide, il n'y a rien à publier + + + SMESH_DX + dX + + + SMESH_DY + dY + + + SMESH_DZ + dZ + + + SMESH_ELEM0D + Elément 0D + + + SMESH_EDGE + Arête + + + SMESH_EDGES_CONNECTIVITY_TITLE + Connectivité des arêtes + + + SMESH_EDIT_GROUP_TITLE + Editer un groupe + + + SMESH_EDIT_GEOMGROUP_AS_GROUP_TITLE + Editer un groupe en tant qu'autonome + + + SMESH_EDIT_HYPOTHESES + Attribuer les hypothèses + + + SMESH_EDIT_USED + Utilisé + + + SMESH_ELEMENTS + Eléments + + + SMESH_ELEMENTS_COLOR + Couleur des éléments du maillage + + + SMESH_ELEMENTS_TYPE + Type des éléments + + + SMESH_ELEMENT_TYPE + Type de l'élément + + + SMESH_ERROR + Erreur + + + SMESH_ERR_SCALARBAR_PARAMS + Avertissement! Les paramètres ne sont pas corrects + + + SMESH_EXPORT_FAILED + Impossible d'exporter le maillage. +Vérifiez l'espace disponible sur le disque. + + + SMESH_EXPORT_MED_DUPLICATED_GRP + Il y a des noms de groupes dupliqués dans le maillage "%1". +Vous pouvez annuler l'exportation et les renommer, +si non des noms de groupes au fichier MED résultant +ne correspondront pas aux noms de l'étude. +Voulez-vous continuer ? + + + SMESH_EXPORT_MED_DUPLICATED_MESH_NAMES + Il y a des maillages avec les mêmes noms dans la sélection. +Il est possible que le fichier résultant soit incorrect. +Voulez-vous continuer ? + + + SMESH_EXPORT_MED_V2_1 + Les éléments polygonaux et polyèdriques seront omis dans le cas d'exportation du maillage "%1" à MED 2.1 +Utilisez MED 2.2 pour l'exportation correcte. +Voulez-vous effectuer l'exportation à MED 2.1 ? + + + SMESH_EXPORT_MED_VERSION_COLLISION + La version MED du fichier "%1" n'est pas connue ou ne correspond pas à la version choisie. +Réécrire le fichier ? + + + SMESH_EXPORT_MED_MESH_NAMES_COLLISION + Le fichier choisi contient déjà +les maillages avec les noms suivants: %1 +Il est possible que le fichier résultant ne soit pas correct. +Réécrire le fichier ? + + + SMESH_EXPORT_STL1 + Le maillage - "%1" ne contient pas de triangles + + + SMESH_EXPORT_STL2 + Le maillage - "%1" contient d'autres éléments que les triangles, ils ne seront donc pas enregistrés dans le fichier STL + + + SMESH_EXPORT_UNV + Les éléments pyramides seront omis au cours de l'exportation du maillage "%1" dans le fichier UNV + + + SMESH_EXTRUSION + Extrusion + + + SMESH_EXTRUSION_TO_DISTANCE + Distance de l'extrusion + + + SMESH_EXTRUSION_ALONG_VECTOR + Extrusion le long du vecteur + + + SMESH_FACE + Face + + + SMESH_FEATUREANGLE + Montrer l'angle + + + SMESH_FEATUREEDGES + Montrer les arêtes + + + SMESH_FILE_EXISTS + Le fichier "%1" existe déjà. +Voulez-vous le réécrire ou y ajouter les données exportées ? + + + SMESH_FONT_ARIAL + Arial + + + SMESH_FONT_BOLD + Gras + + + SMESH_FONT_COURIER + Courrier + + + SMESH_FONT_ITALIC + Italique + + + SMESH_FONT_SCALARBAR + Police + + + SMESH_FONT_SHADOW + Ombrage + + + SMESH_FONT_TIMES + Times + + + SMESH_GEOM_GROUP + Groupe géométrique + + + SMESH_GROUP + Groupe + + + SMESH_GROUP_GEOMETRY + Groupe lié à la géométrie + + + SMESH_GROUP_SELECTED + %1 groupes + + + SMESH_GROUP_STANDALONE + Groupe autonome + + + SMESH_GROUP_TYPE + Type du groupe + + + SMESH_HEIGHT + Hauteur : + + + SMESH_HEXAS + Hexaèdre + + + SMESH_HILIGHT_COLOR + Couleur de sélection + + + SMESH_HORIZONTAL + Horizontale + + + SMESH_HYPOTHESES + Hypothèses + + + SMESH_HYP_1 + Il manque une hypothèse à l'algorithme + + + SMESH_HYP_10 + L'hypothèse ne correspond pas aux dimensions du sous-maillage + + + SMESH_HYP_11 + La géométrie n'est ni la géométrie principale, ni un de ses sous-objets, ni un groupe valide + + + SMESH_HYP_12 + La géométrie ne correspond pas à l'algorithme +Référez-vous à la documentation sur l'algorithme et la géométrie supportée + + + SMESH_HYP_13 + L'algorithme ne peut pas opérer sans géométrie + + + SMESH_HYP_2 + Il y a des hypothèses concurrentes sur la géométrie + + + SMESH_HYP_3 + L'hypothèse contient une valeur de paramètre incorrecte + + + SMESH_HYP_4 + Le sous-maillage n'est pas pris en compte parce qu'il y a un algorithme de dimension supérieure pour générer les éléments %1D + + + SMESH_HYP_5 + L'algorithme l'emporte sur les algorithme(s) de dimensions inférieures en générant les éléments de toutes les dimensions + + + SMESH_HYP_6 + Erreur critique inconnue lors de la définition de l'hypothèse + + + SMESH_HYP_7 + L'hypothèse ne correspond pas à la situation actuelle + + + SMESH_HYP_8 + Un maillage non-conforme a été produit avec les hypothèses appliquées + + + SMESH_HYP_9 + L'hypothèse d'une telle dimension est déjà attribuée à la géométrie + + + SMESH_ID_DIAGONAL + IDs des arêtes + + + SMESH_ID_ELEMENTS + IDs des éléments + + + SMESH_ID_FACES + IDs des faces + + + SMESH_ID_NODES + IDs des nœuds + + + SMESH_INCORRECT_INPUT + Les données d'entrée ne sont pas correctes + + + SMESH_INFORMATION + Information + + + SMESH_INIT + Maillage + + + SMESH_INIT_MESH + Construction du maillage + + + SMESH_INSUFFICIENT_DATA + La valeur d'entrée n'est pas suffisante + + + SMESH_LABELS + Etiquettes : + + + SMESH_LABELS_COLORS_SCALARBAR + Couleurs && étiquettes + + + SMESH_LENGTH + Longueur + + + SMESH_MAKE_GROUPS + Générer les groupes + + + SMESH_MANIFOLDEDGES + Arêtes partagées + + + SMESH_MAX + Max + + + SMESH_MEN_ALGORITHMS + Algorithmes + + + SMESH_MEN_APPLIED_ALGORIHTMS + Algorithmes appliqués + + + SMESH_MEN_APPLIED_HYPOTHESIS + Hypothèses appliquées + + + SMESH_MEN_COMPONENT + SMESH + + + SMESH_MEN_HYPOTHESIS + Hypothèses + + + SMESH_MEN_SubMeshesOnCompound + Sous-maillages sur un assemblage + + + SMESH_MEN_SubMeshesOnEdge + Sous-maillages sur une arête + + + SMESH_MEN_SubMeshesOnFace + Sous-maillages sur une face + + + SMESH_MEN_SubMeshesOnSolid + Sous-maillages sur un solide + + + SMESH_MEN_SubMeshesOnVertex + Sous-maillages sur un point + + + SMESH_AUTOMATIC + Automatique + + + SMESH_MANUAL + Manuel + + + SMESH_MERGE_ELEMENTS + Fusionner les éléments + + + SMESH_MODE + Mode + + + SMESH_MERGED_ELEMENTS + %1 éléments fusionnés avec succès + + + SMESH_MERGED_NODES + %1 nœuds fusionnés avec succès + + + SMESH_NO_ELEMENTS_DETECTED + Il n'y a aucun élément à fusionner. + + + SMESH_NO_NODES_DETECTED + Il n'y a aucun nœud à fusionner + + + SMESH_MERGE_NODES + Fusionner les nœuds + + + SMESH_MESH + Maillage + + + SMESH_MESHINFO_0DELEMS + Eléments 0D + + + SMESH_MESHINFO_ALL_TYPES + Hétérogène + + + SMESH_MESHINFO_EDGES + Arêtes + + + SMESH_MESHINFO_ELEMENTS + Eléments + + + SMESH_MESHINFO_ENTITIES + Entités + + + SMESH_MESHINFO_FACES + Faces + + + SMESH_MESHINFO_HEXAS + Hexaèdres + + + SMESH_MESHINFO_NAME + Nom + + + SMESH_MESHINFO_NODES + Nœuds + + + SMESH_MESHINFO_ORDER0 + Total + + + SMESH_MESHINFO_ORDER1 + Linéaire + + + SMESH_MESHINFO_ORDER2 + Quadratique + + + SMESH_MESHINFO_POLYEDRES + Polyèdres + + + SMESH_MESHINFO_POLYGONES + Polygones + + + SMESH_MESHINFO_PRISMS + Prismes + + + SMESH_MESHINFO_PYRAS + Pyramides + + + SMESH_MESHINFO_QUADRANGLES + Quadrangles + + + SMESH_MESHINFO_TETRAS + Tetraèdres + + + SMESH_MESHINFO_TITLE + Informations sur le maillage + + + SMESH_MESHINFO_TOTAL + Total + + + SMESH_MESHINFO_TRIANGLES + Triangles + + + SMESH_MESHINFO_TYPE + Type + + + SMESH_MESHINFO_VOLUMES + Volumes + + + SMESH_MIN + Min + + + SMESH_MOVE + Déplacer + + + SMESH_MOVE_ELEMENTS + Déplacer les éléments + + + SMESH_MOVE_NODES_TITLE + Déplacer un nœud + + + SMESH_NAME + Nom + + + SMESH_NODES + Nœuds + + + SMESH_NONMANIFOLDEDGES + Arêtes non-partagées + + + SMESH_NORMAL + Normal + + + SMESH_NO_MESH_VISUALIZATION + Il n'y a pas assez de mémoire pour visualiser le maillage + + + SMESH_NUMBEROFCOLORS + Nombre de couleurs : + + + SMESH_NUMBEROFLABELS + Nombre d'étiquettes : + + + SMESH_NUMBEROFSTEPS + Nombre de pas : + + + SMESH_OBJECTS_SELECTED + %1_objets + + + SMESH_OBJECT_ALGORITHM + Algorithme + + + SMESH_OBJECT_GEOM + Objet géométrique + + + SMESH_OBJECT_HYPOTHESIS + Hypothèse + + + SMESH_OBJECT_MESH + Maillage + + + SMESH_OBJECT_MESHorSUBMESH + Maillage ou sous-maillage + + + SMESH_OPERATION_FAILED + L'opération n'a pas abouti + + + SMESH_ORIENTATION + Orientation + + + SMESH_ORIENTATION_ELEMENTS_TITLE + Changer l'orientation + + + SMESH_OUTLINE_COLOR + Couleur de l'objet maillage + + + SMESH_PARAMETERS + Paramètres + + + SMESH_PLANE + Plan + + + SMESH_POINT + Point + + + SMESH_POINT_1 + Point 1 + + + SMESH_POINT_2 + Point 2 + + + SMESH_BASE_POINT + Point de base + + + SMESH_POLYEDRE_CREATE_ERROR + Erreur de création du polyèdre + + + SMESH_POLYEDRON + Polyèdre + + + SMESH_POLYGON + Polygone + + + SMESH_POSITION_SIZE_SCALARBAR + Origine && Taille + + + SMESH_PRECISION + Précision + + + SMESH_PREFERENCES_SCALARBAR + Préférences de la barre d'échelle + + + SMESH_PREF_SELECTION + Préférences - Sélection + + + SMESH_PRESELECTION + Présélection + + + SMESH_PRISM + Prisme + + + SMESH_PROPERTIES_SCALARBAR + Proprétés de la barre d'échelle + + + SMESH_PYRAMID + Pyramide + + + SMESH_QUADRANGLE + Quadrangle + + + SMESH_QUADRATIC_EDGE + Arête quadratique + + + SMESH_QUADRATIC_HEXAHEDRON + Hexaèdre quadratique + + + SMESH_QUADRATIC_PENTAHEDRON + Pentaèdre quadratique + + + SMESH_QUADRATIC_PYRAMID + Pyramide quadratique + + + SMESH_QUADRATIC_QUADRANGLE + Quadrangle quadratique + + + SMESH_QUADRATIC_TETRAHEDRON + Tetraèdre quadratique + + + SMESH_QUADRATIC_TRIANGLE + Triangle quadratique + + + SMESH_RANGE_MAX + Valeur maximale : + + + SMESH_RANGE_MIN + Valeur minimale : + + + SMESH_RANGE_SCALARBAR + Echelle de valeurs + + + SMESH_REALLY_DELETE + Voulez-vous vraiment supprimer ces %1 objets? : %2 + + + SMESH_REMOVE + Supprimer + + + SMESH_REMOVE_ELEMENTS_TITLE + Supprimer les éléments + + + SMESH_REMOVE_NODES_TITLE + Supprimer les nœuds + + + SMESH_RENUMBERING + Renuméroter + + + SMESH_RENUMBERING_ELEMENTS_TITLE + Renuméroter les éléments + + + SMESH_RENUMBERING_NODES_TITLE + Renuméroter les nœuds + + + SMESH_REVERSE + Inverser + + + SMESH_REVOLUTION + Révolution + + + SMESH_RM_HYP_WRN + "%1" n'est pas attribué, mais: + + + + SMESH_ROTATION + Rotation + + + SMESH_ROTATION_TITLE + Rotation autour d'un axe + + + SMESH_SCALARBAR + Barre d'échelle + + + SMESH_SEGMENTS + Segments + + + SMESH_SELECTION + Sélection + + + SMESH_SELECT_FROM + Sélectionner à partir de + + + SMESH_SELECT_WHOLE_MESH + Choisir un maillage entier, un sous-maillage ou un groupe + + + SMESH_SET_COLOR + Groupe de couleur + + + SMESH_SEWING + Couture + + + SMESH_SMOOTHING + Lissage + + + SMESH_STANDARD_MESHINFO_TITLE + Information de maillage + + + SMESH_SUBMESH + Sous-maillage + + + SMESH_SUBMESH_SELECTED + %1 sous-maillages + + + SMESH_SYMMETRY + Symétrie + + + SMESH_TETRAS + Tétraèdre + + + SMESH_TITLE + Titre : + + + SMESH_TOLERANCE + Tolérance + + + SMESH_TRANSLATION + Translation + + + SMESH_SCALE_TITLE + Transformation d'échelle + + + SMESH_DUPLICATE_TITLE + Dupliquer les nœuds + + + SMESH_SCALE + Echelle + + + SMESH_SCALE_FACTOR + Facteur d'échelle : + + + SMESH_SCALE_FACTOR_X + Facteur d'échelle X : + + + SMESH_SCALE_FACTOR_Y + Facteur d'échelle Y : + + + SMESH_SCALE_FACTOR_Z + Facteur d'échelle Z : + + + SMESH_TRANSPARENCY_OPAQUE + → Opaque + + + SMESH_TRANSPARENCY_TITLE + Changer la transparence + + + SMESH_TRANSPARENCY_TRANSPARENT + Transparent ← + + + SMESH_TRIANGLE + Triangle + + + SMESH_UPDATEVIEW + Mettre à jour la vue + + + SMESH_VALUE + Valeur + + + SMESH_VECTOR + Vecteur + + + SMESH_VERTICAL + Verticale + + + SMESH_VISU_PROBLEM + Impossible de visualiser le maillage, probablement à cause d'un manque de mémoire + + + SMESH_VISU_PROBLEM_CLEAR + Impossible de visualiser le maillage, pas assez de la mémoire pour montrer le message, +donc toutes les données visuelles ont été supprimées pour ne pas planter l'application. +Enregistrez votre travail avant que l'application se plante + + + SMESH_VOLUME + Volume + + + SMESH_WARNING + Avertissement + + + SMESH_WHAT_IS_TITLE + Information sur un élément de maillage + + + SMESH_WIDTH + Largeur : + + + SMESH_WRN_ALGORITHM_ALREADYEXIST + L'algorithme existe déjà + + + SMESH_WRN_COMPUTE_FAILED + Impossible de calculer le maillage + + + SMESH_WRN_EVALUATE_FAILED + Impossible d'évaluer le maillage + + + SMESH_WRN_EMPTY_NAME + Un nom vide n'est pas valide + + + SMESH_WRN_HYPOTHESIS_ALREADYEXIST + L'hypothèse existe déjà + + + SMESH_WRN_HYPOTHESIS_NOTEXIST + L'hypothèse ou l'algorithme n'existent pas + + + SMESH_WRN_MISSING_PARAMETERS + Paramètres manquants + + + SMESH_WRN_NO_AVAILABLE_DATA + Pas de données disponibles dans la sélection + + + SMESH_WRN_SELECTIONMODE_DIAGONAL + Activer le mode de sélection des références + + + SMESH_WRN_SELECTIONMODE_ELEMENTS + Activer le mode de sélection des éléments + + + SMESH_WRN_SELECTIONMODE_NODES + Activer le mode de sélection des nœuds + + + SMESH_WRN_VIEWER_VTK + Il faut ouvrir la scène dans le visualisateur VTK + + + SMESH_WRN_SIZE_LIMIT_EXCEEDED + La présentation n'a pas été mise à jour automatiquement: la nouvelle taille du maillage (%1 éléments) dépasse la limite de taille actuelle (%2 éléments). +Vérifiez la limite dans les préférences du module Mesh. + + + + SMESH_WRN_WARNING + Avertissement + + + SMESH_X + X + + + SMESH_X_SCALARBAR + X : + + + SMESH_Y + Y + + + SMESH_Y_SCALARBAR + Y : + + + SMESH_Z + Z + + + STATE_ALGO_MISSING + Il manque l'algorithme %3 %2D + + + STATE_HYP_BAD_GEOMETRY + L'algorithme %3 %2D "%1" est attribué à une géométrie qui ne convient pas + + + STATE_HYP_BAD_PARAMETER + Il y a un paramètre incorrect dans l'hypothèse %3 %2D de l'algorithme "%1" + + + STATE_HYP_MISSING + L'hypothèse %4D manque à l'algorithme %3 %2D "%1" + + + STATE_HYP_NOTCONFORM + L'algorithme %3 %2D "%1" produit un maillage non-conforme: l'hypothèse globale "Maillage non conforme autorisé" doit être cochée + + + STB_ADV_INFO + Information avancée sur le maillage + + + STB_ALL + Tous + + + STB_AREA + Aire + + + STB_ASPECT + Rapport de forme + + + STB_ASPECT_3D + Rapport de forme 3D + + + STB_AUTO_COLOR + Couleur automatique + + + STB_AUTO_UPD + Mise à jour automatique + + + STB_BUILD_COMPOUND + Construire un maillage assemblé + + + STB_CLIP + Pan de coupe + + + STB_COLORS + Couleurs / Taille + + + STB_COMPUTE + Calculer + + + STB_PRECOMPUTE + Prévisualiser + + + STB_EVALUATE + Evaluer + + + STB_CONNECTION + Frontières sur connection multiples + + + STB_CONNECTION_2D + Frontières sur connection multiples 2D + + + STB_CONSTRUCT_GROUP + Construire un groupe + + + STB_CONV_TO_QUAD + Convertir vers/de quadratique + + + STB_2D_FROM_3D + Créer les éléments de frontière + + + STB_MESH_ORDER + Changer la priorité des sous-maillages + + + STB_CREATE_GROUP + Créer un groupe + + + STB_CREATE_GEO_GROUP + Créer les groupes à partir de la géométrie + + + STB_CREATE_MESH + Créer un maillage + + + STB_CREATE_SUBMESH + Créer un sous-maillage + + + STB_CUT + Découpe des quadrangles + + + STB_CUT_GROUP + Découper les groupes + + + STB_DAT + Importer un fichier DAT + + + STB_DELETE + Supprimer + + + STB_DEL_GROUP + Supprimer les groupes + + + STB_FACE_ORIENTATION + Orientation des faces + + + STB_DISABLE_AUTO_COLOR + Désactiver la couleur automatique + + + STB_DISPLAY_ONLY + Afficher uniquement + + + STB_DISP_ENT + Visualiser une entité + + + STB_ELEM0D + Elément 0D + + + STB_ELEMS0D + Eléments 0D + + + STB_EDGE + Arête + + + STB_EDGES + Arêtes + + + STB_EDIT_GROUP + Editer un groupe + + + STB_EDIT_GEOMGROUP_AS_GROUP + Editer un groupe en tant qu'autonome + + + STB_EDIT_HYPO + Editer une hypothèse + + + STB_EDIT_MESHSUBMESH + Editer un maillage/sous-maillage + + + STB_EXPORT_DAT + Exporter au format DAT + + + STB_EXPORT_MED + Exporter au format MED + + + STB_EXPORT_SAUV + Exporter au format SAUV (ASCII) + + + STB_EXPORT_STL + Exporter au format STL + + + STB_EXPORT_UNV + Exporter au format UNV + + + STB_EXTRUSION + Extrusion + + + STB_EXTRUSION_ALONG + Extrusion suivant un chemin + + + STB_FACES + Faces + + + STB_FREE_BORDER + Frontières libres + + + STB_FREE_EDGE + Arêtes libres + + + STB_FREE_NODE + Nœuds libres + + + STB_FREE_FACES + Faces libres + + + STB_GLOBAL_HYPO + Hypothèse globale + + + STB_HEXA + Hexaèdre + + + STB_HIDE + Cacher + + + STB_INT_GROUP + Intersection des groupes + + + STB_INV + Inversion de diagonale + + + STB_LENGTH + Longueur + + + STB_LENGTH_2D + Longueur 2D + + + STB_MAP + Projection de motif + + + STB_MED + Importer un fichier MED + + + STB_SAUV + Importer un fichier SAUV (ASCII) + + + STB_MERGE + Fusionner les nœuds + + + STB_MERGE_ELEMENTS + Fusionner les éléments + + + STB_MESH_THROU_POINT + Déplacer un nœud + + + STB_MIN_ANG + Angle minimal + + + STB_MOVE + Déplacer un nœud + + + STB_NODE + Nœud + + + STB_NODES + Nœuds + + + STB_NUM_ELEMENTS + Visualiser les éléments + + + STB_NUM_NODES + Visualiser les nœuds + + + STB_ORIENT + Orientation + + + STB_POLYGON + Polygone + + + STB_POLYHEDRON + Polyèdre + + + STB_PRECISION + Précision + + + STB_QUAD + Quadrangle + + + STB_QUADRATIC_EDGE + Arête quadratique + + + STB_QUADRATIC_HEXAHEDRON + Hexaèdre quadratique + + + STB_QUADRATIC_PENTAHEDRON + Pentaèdre quadratique + + + STB_QUADRATIC_PYRAMID + Pyramide quadratique + + + STB_QUADRATIC_QUADRANGLE + Quadrangle quadratique + + + STB_QUADRATIC_TETRAHEDRON + Tétraèdre quadratique + + + STB_QUADRATIC_TRIANGLE + Triangle quadratique + + + STB_REMOVE_ELEMENTS + Supprimer les éléments + + + STB_REMOVE_NODES + Supprimer les nœuds + + + STB_REMOVE_ORPHAN_NODES + Supprimer les nœuds orphelins + + + STB_RENAME + Renommer + + + STB_RENUM_ELEMENTS + Renuméroter les éléments + + + STB_RENUM_NODES + Renuméroter les nœuds + + + STB_RESET + Restaurer + + + STB_REVOLUTION + Révolution + + + STB_ROT + Rotation + + + STB_SCALAR_BAR + Barre d'échelle + + + STB_SCALAR_BAR_PROP + Propriétés de la barre d'échelle + + + STB_SELECTION + Sélection + + + STB_SEL_FILTER_LIB + Librairie des filtres de sélection + + + STB_SEW + Couture + + + STB_SHADE + Ombrage + + + STB_SHOW + Visualiser + + + STB_SHRINK + Contraction + + + STB_SKEW + Inclinaison d'angle + + + STB_SMOOTH + Lissage + + + STB_STD_INFO + Informations du maillage + + + STB_SYM + Symétrie + + + STB_TAPER + Cône + + + STB_TETRA + Tétraèdre + + + STB_TRANS + Translation + + + STB_SCALE + Mise à l'échelle + + + STB_DUPLICATE_NODES + Dupliquer les nœuds + + + STB_TRANSP + Transparence + + + STB_TRIANGLE + Triangle + + + STB_UNASSIGN + Désassocier + + + STB_UNION + Union des triangles + + + STB_UNION2 + Union de deux triangles + + + STB_UNV + Importer un fichier UNV + + + STB_UN_GROUP + Union des groupes + + + STB_UNDERLYING_ELEMS + Créer les groupes d'entités à partir des groupes existants de dimensions supérieures + + + STB_UPDATE + Mettre à jour + + + STB_VOLUMES + Volumes + + + STB_VOLUME_3D + Volume + + + STB_WARP + Angle de déformation + + + STB_WHAT_IS + Information sur l'élément de maillage + + + STB_WIRE + Contour + + + TAPER_ELEMENTS + Cône + + + TB_ADD_REMOVE + Ajouter/supprimer la barre d'outils + + + TB_CTRL + Barre d'outils des contrôles + + + TB_DISP_MODE + Barre du mode de visualisation + + + TB_HYPO + Barre d'hypothèses + + + TB_MESH + Barre de maillage + + + TB_MODIFY + Barre des modifications + + + TOP_ADV_INFO + Informations avancées du maillage + + + TOP_ALL + Tous + + + TOP_AREA + Aire + + + TOP_ASPECT + Rapport de forme + + + TOP_ASPECT_3D + Rapport de forme 3D + + + TOP_AUTO_COLOR + Couleur automatique + + + TOP_AUTO_UPD + Mise à jour automatique + + + TOP_BUILD_COMPOUND + Construire un maillage assemblé + + + TOP_CLIP + Plan de coupe + + + TOP_COLORS + Couleurs / Taille + + + TOP_COMPUTE + Calculer + + + TOP_PRECOMPUTE + Prévisualiser + + + TOP_EVALUATE + Evaluer + + + TOP_CONNECTION + Frontières sur connections multiples + + + TOP_CONNECTION_2D + Frontières sur connections multiples 2D + + + TOP_CONSTRUCT_GROUP + Construire un groupe + + + TOP_CONV_TO_QUAD + Convertir vers/de quadratique + + + TOP_2D_FROM_3D + Créer les éléments de frontière + + + TOP_MESH_ORDER + Changer la priorité des sous-maillages + + + TOP_CREATE_GROUP + Créer un groupe + + + TOP_CREATE_GEO_GROUP + Créer les groupes liés à la géométrie + + + TOP_CREATE_MESH + Créer un maillage + + + TOP_CREATE_SUBMESH + Créer un sous-maillage + + + TOP_CUT + Découpe des quadrangles + + + TOP_CUT_GROUP + Découper les groupes + + + TOP_DAT + Importer un fichier DAT + + + TOP_DELETE + Supprimer + + + TOP_DEL_GROUP + Supprimer les groupes + + + TOP_FACE_ORIENTATION + Orientation des faces + + + TOP_DISABLE_AUTO_COLOR + Désactiver la couleur automatique + + + TOP_DISPLAY_ONLY + Afficher uniquement + + + TOP_DISP_ENT + Visualiser une entité + + + TOP_ELEM0D + Elément 0D + + + TOP_ELEMS0D + Eléments 0D + + + TOP_EDGE + Arête + + + TOP_EDGES + Arêtes + + + TOP_EDIT_GROUP + Editer un groupe + + + TOP_EDIT_GEOMGROUP_AS_GROUP + Editer un groupe en tant qu'autonome + + + TOP_EDIT_HYPO + Editer l'hypothèse + + + TOP_EDIT_MESHSUBMESH + Editer un maillage/sous-maillage + + + TOP_EXPORT_DAT + Exporter au format DAT + + + TOP_EXPORT_MED + Exporter au format MED + + + TOP_EXPORT_SAUV + Exporter au format SAUV (ASCII) + + + TOP_EXPORT_STL + Exporter au format STL + + + TOP_EXPORT_UNV + Exporter au format UNV + + + TOP_EXTRUSION + Extrusion + + + TOP_EXTRUSION_ALONG + Extrusion suivant un chemin + + + TOP_FACES + Faces + + + TOP_FREE_BORDER + Frontières libres + + + TOP_FREE_EDGE + Arêtes libres + + + TOP_FREE_NODE + Nœuds libres + + + TOP_FREE_FACES + Faces libres + + + TOP_GLOBAL_HYPO + Hypothèse globale + + + TOP_HEXA + Hexaèdre + + + TOP_HIDE + Cacher + + + TOP_INT_GROUP + Intersection de groupes + + + TOP_INV + Inversion de diagonale + + + TOP_LENGTH + Longueur + + + TOP_LENGTH_2D + Longueur 2D + + + TOP_MAP + Projection de motif + + + TOP_MED + Importer un fichier MED + + + TOP_SAUV + Importer un fichier SAUV (ASCII) + + + TOP_MERGE + Fusionner les nœuds + + + TOP_MERGE_ELEMENTS + Fusionner les éléments + + + TOP_MESH_THROU_POINT + Déplacer un nœud + + + TOP_MIN_ANG + Angle minimal + + + TOP_MOVE + Déplacer un nœud + + + TOP_NODE + Nœud + + + TOP_NODES + Nœuds + + + TOP_NUM_ELEMENTS + Visualiser les éléments + + + TOP_NUM_NODES + Visualiser les nœuds + + + TOP_ORIENT + Orientation + + + TOP_POLYGON + Polygone + + + TOP_POLYHEDRON + Polyèdre + + + TOP_PRECISION + Précision + + + TOP_QUAD + Quadrangle + + + TOP_QUADRATIC_EDGE + Arête quadratique + + + TOP_QUADRATIC_HEXAHEDRON + Hexaèdre quadratique + + + TOP_QUADRATIC_PENTAHEDRON + Pentaèdre quadratique + + + TOP_QUADRATIC_PYRAMID + Pyramide quadratique + + + TOP_QUADRATIC_QUADRANGLE + Quadrangle quadratique + + + TOP_QUADRATIC_TETRAHEDRON + Tétraèdre quadratique + + + TOP_QUADRATIC_TRIANGLE + Triangle quadratique + + + TOP_REMOVE_ELEMENTS + Supprimer les éléments + + + TOP_REMOVE_NODES + Supprimer les nœuds + + + TOP_REMOVE_ORPHAN_NODES + Supprimer les nœuds ophelins + + + TOP_RENAME + Renommer + + + TOP_RENUM_ELEMENTS + Renuméroter les éléments + + + TOP_RENUM_NODES + Renuméroter les nœuds + + + TOP_RESET + Restaurer + + + TOP_REVOLUTION + Révolution + + + TOP_ROT + Rotation + + + TOP_SCALAR_BAR + Barre d'échelle + + + TOP_SCALAR_BAR_PROP + Propriétés de la barre d'échelle + + + TOP_SELECTION + Sélection + + + TOP_SEL_FILTER_LIB + Librairie des filtres de sélection + + + TOP_SEW + Couture + + + TOP_SHADE + Ombrage + + + TOP_SHOW + Visualiser + + + TOP_SHRINK + Contraction + + + TOP_SKEW + Inclinaison d'angle + + + TOP_SMOOTH + Lissage + + + TOP_STD_INFO + Informations du maillage + + + TOP_SYM + Symétrie + + + TOP_TAPER + Cône + + + TOP_TETRA + Tétraèdre + + + TOP_TRANS + Translation + + + TOP_SCALE + Mise à l'échelle + + + TOP_DUPLICATE_NODES + Dupliquer les nœuds + + + TOP_TRANSP + Transparence + + + TOP_TRIANGLE + Triangle + + + TOP_UNASSIGN + Désassocier + + + TOP_UNION + Union des triangles + + + TOP_UNION2 + Union de deux triangles + + + TOP_UNV + Importer un fichier UNV + + + TOP_UN_GROUP + Union des groupes + + + TOP_UNDERLYING_ELEMS + Créer les groupes d'entités à partir des groupes existants de dimensions supérieures + + + TOP_UPDATE + Mettre à jour + + + TOP_VOLUMES + Volumes + + + TOP_VOLUME_3D + Volume + + + TOP_WARP + Angle de déformation + + + TOP_WHAT_IS + Information sur l'élément de maillage + + + TOP_WIRE + Contours + + + VOLUME_3D_ELEMENTS + Aire + + + WARP_ELEMENTS + Déformation + + + MEN_FILE_INFO + Information du fichier MED + + + SMESH_WRN_NO_APPROPRIATE_SELECTION + Aucun objet sélectionné ne convient + + + MEN_CLEAR_MESH + Effacer les données du maillage + + + TOP_CLEAR_MESH + Effacer les données du maillage + + + STB_CLEAR_MESH + Effacer les données du maillage + + + SMESH_IMPORT_MESH + Importer les donnés du maillage à partir des fichiers + + + SMESH_ERR_NOT_SUPPORTED_FORMAT + Le format de fichier n'est pas supporté + + + SMESH_ERR_UNKNOWN_IMPORT_ERROR + Erreur inconnue + + + SMESH_IMPORT_ERRORS + L'importation s'est terminée avec des erreurs + + + SMESH_DRS_SOME_EMPTY + Un ou plusieurs fichiers de maillage sont vides, les données n'ont pas été publiées + + + NO_MESH_SELECTED + Aucun maillage sélectionné + + + SMESH_PREF_def_precision + Précision par défaut + + + SMESH_PREF_length_precision + Précision de la longueur + + + SMESH_PREF_angle_precision + Précision angulaire + + + SMESH_PREF_len_tol_precision + Précision de tolérance de la longueur + + + SMESH_PREF_parametric_precision + Précision paramétrique + + + SMESH_PREF_area_precision + Précision de l'aire + + + FULL_RECOMPUTE_QUESTION + +Le maillage a été édité après le dernier calcul complet, +ceci peut empêcher un calcul correct. +Voulez-vous recalculer le maillage entier pour rejeter les modifications ? + + + + SMESH_PREF_vol_precision + Précision du volume + + + SMESH_PRECISION_HINT + +Il est possible de modifier la précision de la valeur d'entrée +avec le paramètre '%1' des préférences du module Mesh. + + + REMOVE_ORPHAN_NODES_QUESTION + Voulez-vous supprimer tous les nœuds orphelins ? + + + NB_NODES_REMOVED + %1 nœud(s) supprimés. + + + SMESH_PLUGINS_OTHER + Extensions SMESH + + + + SMESHGUI + + NOT_A_VTK_VIEWER + Cette commande n'est disponible qu'à partir d'une fenêtre VTK. +Ouvrez une fenêtre VTK et essayez de nouveau + + + PREF_AUTO_GROUPS + Créer les groupes automatiquement pour l'export MED + + + PREF_GROUP_SEGMENT_LENGTH + Paramètres automatiques + + + PREF_SEGMENT_LENGTH + Ratio de la diagonale de la boîte englobante / taille maximale + + + PREF_NB_SEGMENTS + Nombre de segments par défaut + + + PREF_AUTO_UPDATE + Mettre à jour automatiquement + + + PREF_UPDATE_LIMIT + Limite de taille (nombre d'éléments) + + + PREF_UPDATE_LIMIT_NOLIMIT + Sans limite + + + PREF_BACKFACE + Face arrière + + + PREF_COLOR + Couleur + + + PREF_ORIENTATION_COLOR + Couleur + + + PREF_ORIENTATION_3D_VECTORS + Vecteurs 3D + + + PREF_ORIENTATION_SCALE + Echelle + + + PREF_DISPLAY_ENTITY + Eléments à visualiser + + + QUADRATIC_REPRESENT_MODE + Représentation des éléments quadratiques 2D + + + MAX_ARC_ANGLE + Angle maximal + + + PREF_DISPLAY_MODE + Mode de visualisation + + + PREF_ELEMENTS + Eléments + + + PREF_ELEMENT_COLOR + Couleur d'élément + + + PREF_FILL + Remplir + + + PREF_NOTIFY_MODE + Montrer la notification sur le résultat de calcul + + + SMESH_PREF_GROUP_PRECISION + Précision des champs d'entrée + + + PREF_GROUP_ELEMENTS + Eléments + + + PREF_GROUP_EXPORT + Exporter un maillage + + + PREF_GROUP_FACES_ORIENTATION + Orientation des faces + + + PREF_GROUP_COMPUTE + Calculer le maillage + + + PREF_GROUP_NODES + Nœuds + + + PREF_GROUP_GROUPS + Groupes + + + PREF_GRP_NAMES + Couleur des noms + + + PREF_GROUP_PRECISION + Précision + + + PREF_GROUP_PRESELECTION + Présélection + + + PREF_GROUP_QUALITY + Contrôles de qualité + + + PREF_GROUP_SELECTION + Sélection + + + PREF_HIGHLIGHT_COLOR + Couleur de sélection + + + PREF_LABELS_COLOR + Couleur des étiquettes + + + PREF_MARKER_SCALE + Echelle du marqueur + + + PREF_NODES + Nœuds + + + PREF_OBJECTS + Objets + + + PREF_OBJECT_COLOR + Couleur d'objet + + + PREF_OUTLINE + Silhouette + + + PREF_PRECISION_USE + Utiliser la précision + + + PREF_PRECISION_VALUE + Nombre de chiffres après la virgule + + + PREF_RENUMBER + Renuméroter automatiquement + + + PREF_SHRINK_COEFF + Coefficient de contraction + + + PREF_TAB_GENERAL + Général + + + PREF_TAB_MESH + Maillage + + + PREF_TAB_SELECTION + Sélection + + + PREF_TITLE_COLOR + Couleur du titre + + + PREF_TYPE_OF_MARKER + Type de marqueur + + + PREF_COLOR_0D + Eléments 0D + + + PREF_SIZE_0D + Taille des éléments 0D + + + PREF_WIDTH + Epaisseur + + + + SMESHGUI_AddQuadraticElementDlg + + SMESH_ADD_QUADRATIC_EDGE + Ajouter une arête quadratique + + + SMESH_ADD_QUADRATIC_HEXAHEDRON + Ajouter un hexaèdre quadratique + + + SMESH_ADD_QUADRATIC_PENTAHEDRON + Ajouter un pentaèdre quadratique + + + SMESH_ADD_QUADRATIC_PYRAMID + Ajouter une pyramide quadratique + + + SMESH_ADD_QUADRATIC_QUADRANGLE + Ajouter un quadrangle quadratique + + + SMESH_ADD_QUADRATIC_TETRAHEDRON + Ajouter un tétraèdre quadratique + + + SMESH_ADD_QUADRATIC_TRIANGLE + Ajouter un triangle quadratique + + + SMESH_CORNER_NODES + Nœuds angulaires: + + + SMESH_FIRST + Premier + + + SMESH_LAST + Dernier + + + SMESH_MIDDLE + Milieu + + + + SMESHGUI_BuildCompoundDlg + + COMPOUND + Assemblage + + + COMPOUND_MESH + Maillage d'assemblage + + + CREATE_COMMON_GROUPS + Créer des groupes communs pour les maillages initiaux + + + MERGE_NODES_AND_ELEMENTS + Fusionner les nœuds et les éléments coïncidents + + + MESHES + Maillages + + + PROCESSING_IDENTICAL_GROUPS + Traitement des groupes identiques + + + RENAME + Renommer + + + RESULT_NAME + Nom du résultat + + + UNITE + Réunir + + + + SMESHGUI_ChangeOrientationDlg + + CAPTION + Modifier l'orientation + + + + SMESHGUI_ComputeDlg + + CAPTION + Le calcul du maillage a échoué + + + CONSTRUCTOR + Calculer le maillage + + + EVAL_DLG + Evaluer le maillage + + + ERRORS + Erreurs + + + MEMORY_LACK + Problème d'allocation de mémoire + + + PUBLISH_SHAPE + Publier un sous-objet + + + SHOW_SHAPE + Montrer un sous-objet + + + SHOW_BAD_MESH + Montrer le maillage incorrect + + + + SMESHGUI_PrecomputeDlg + + CAPTION + Prévisualiser et calculer le maillage + + + PREVIEW + Prévisualiser + + + PREVIEW_1 + Maillage 1D + + + PREVIEW_2 + Maillage 2D + + + COMPUTE + Calculer + + + + SMESHGUI_PrecomputeOp + + CLEAR_SUBMESH_QUESTION + Des sous-maillages temporaires ont été créés sur la géométrie sélectionnée +au cours de l'opération de prévisualisation. +Voulez-vous supprimer toutes ces sous-maillages ? + + + SMESH_WRN_NOTHING_PREVIEW + La prévisualisation du maillage n'est pas disponible + + + SMESH_REJECT_MESH_ORDER + La priorité des sous-maillages a été changée au cours de la prévisualisation. +Voulez-vous restaurer la priorité initiale ? + + + + SMESHGUI_ConvToQuadDlg + + CAPTION + Convertir vers/de quadratique + + + MEDIUMNDS + Nœuds milieux sur la géométrie + + + MESH + Maillage + + + RADIOBTN_1 + Convertir en éléments quadratiques + + + RADIOBTN_2 + Convertir à partir d'éléments quadratiques + + + + SMESHGUI_ConvToQuadOp + + MESH_IS_NOT_SELECTED + Le maillage n'est pas sélectionné +Indiquez-le et essayez de nouveau + + + REF_IS_NULL + Aucun maillage valide n'est sélecionné + + + + SMESHGUI_CreatePatternDlg + + CAPTION + Projection de motif + + + DEFAULT_2D + Motif_2d + + + DEFAULT_3D + Motif_3d + + + ERROR_OF_CREATION + Une erreur interne s'est produite au cours de la création du motif +Vérifiez la validité des informations données + + + ERROR_OF_SAVING + Une erreur interne s'est produite au cours de l'enregistrement du motif. +Vérifiez l'espace de disque disponible et vos droits d'écriture dans ce fichier + + + ERR_LOADF_CANT_PROJECT + Impossible d'appliquer la projection des nœuds vers la face + + + ERR_LOADF_CLOSED_FACE + Impossible de créer un motif à partir d'une face avec une arête de couture + + + ERR_LOADF_NARROW_FACE + Impossible de créer un motif à partir d'une face étroite + + + ERR_LOADV_BAD_SHAPE + Il n'est possible de créer un motif que d'une coque fermée ou d'un solide avec 6 faces + + + ERR_LOADV_COMPUTE_PARAMS + Il est impossible de calculer les paramètres du point + + + ERR_LOAD_EMPTY_SUBMESH + Il n'y a pas d'éléments pour créer de motif + + + MESH_OR_SUBMESH + Maillage ou sous-maillage + + + PATTERN + Motif + + + PATTERN_FILT + Fichiers de motif (*.smp) + + + PATTERN_NAME + Nom du motif + + + PATTERN_TYPE + Type du motif + + + PROJECT + Projeter les nœuds sur la face + + + SAVE + Sauvegarder... + + + SAVE_PATTERN + Sauvegarder le motif + + + + SMESHGUI_CreatePolyhedralVolumeDlg + + FACES_BY_NODES + Faces par nœuds + + + SMESH_POLYEDRE_CREATE_ERROR + Erreur de création du polyèdre. + + + SMESH_POLYEDRE_PREVIEW + Prévisualiser le polyèdre + + + + SMESHGUI_CuttingOfQuadsDlg + + CAPTION + Découpe des quadrangles + + + + SMESHGUI_DeleteGroupDlg + + CAPTION + Supprimer les groupes et leur contenu + + + NO_SELECTED_GROUPS + Il n'y a aucun groupe sélectionné +Choisissez un groupe et essayez de nouveau + + + SELECTED_GROUPS + Groupes sélectionnés + + + + SMESHGUI_MergeDlg + + COINCIDENT_ELEMENTS + Eléments coïncidents + + + COINCIDENT_NODES + Nœuds coïncidents + + + DETECT + Détecter + + + EDIT_SELECTED_GROUP + Editer le groupe sélectionné + + + SELECT_ALL + Tout sélectionner + + + EXCLUDE_GROUPS + Exclure les groupes + + + + SMESHGUI_ExtrusionAlongPathDlg + + BAD_SHAPE_TYPE + La géométrie choisie en tant que chemin n'est pas une arête + + + CANT_GET_TANGENT + Impossible d'obtenir la tangente pour un des nœuds du chemin + + + EXTRUSION_1D + Extrusion des éléments 1D + + + EXTRUSION_2D + Extrusion des éléments 2D + + + EXTRUSION_ALONG_PATH + Extrusion suivant un chemin + + + EXTR_BAD_STARTING_NODE + Nœud de départ du chemin incorrect + + + LINEAR_ANGLES + Variation linéaire des angles + + + NO_ELEMENTS_SELECTED + Aucun élément de maillage n'est sélectionné pour l'extrusion + + + SELECTED_PATH_IS_NOT_EDGE + Le maillage du chemin doît être du type arête + + + SMESH_ANGLES + Angles de rotation + + + SMESH_BASE_POINT + Point de base + + + SMESH_PATH + Chemin + + + SMESH_PATH_MESH + Maillage ou sous-maillage + + + SMESH_PATH_SHAPE + Géométrie (arête) + + + SMESH_PATH_START + Nœud de début + + + SMESH_USE_ANGLES + Utiliser les angles + + + SMESH_USE_BASE_POINT + Utiliser le point de base + + + WRONG_ANGLES_NUMBER + Le nombre d'angles doit correspondre au nombre des nœuds du chemin + + + + SMESHGUI_ExtrusionDlg + + EXTRUSION_1D + Extrusion des éléments 1D + + + EXTRUSION_2D + Extrusion des éléments 2D + + + EXTRUSION_ALONG_LINE + Extrusion suivant une ligne + + + + SMESHGUI_FilterDlg + + BAD_SHAPE_NAME + Il n'y a pas d'objet géométrique "%1" dans l'étude actuelle +Sélectionnez un objet valide et essayez de nouveau + + + CURRENT_DIALOG + Groupe actuel + + + EDGES_TLT + Filtre d'arêtes + + + FACES_TLT + Filtre de faces + + + MESH + Maillage + + + NODES_TLT + Filtre de nœuds + + + SELECTION + Sélection initiale + + + SET_IN_VIEWER + Insérer le filtre dans la fenêtre 3D + + + SHAPE_IS_NOT_A_CYLINDER + "%1" n'est pas une face cylindrique +Sélectionnez une face cylindrique et essayez de nouveau + + + SHAPE_IS_NOT_A_FACE + "%1" n'est pas une face +Sélectionnez une face et essayez de nouveau + + + SHAPE_IS_NOT_A_PLANE + "%1" n'est pas un plan +Sélectionnez un plan et essayez de nouveau + + + FACE_ID_NOT_SELECTED + Aucune face de maillage n'est sélectionnée. +Indiquez-la et essayez de nouveau + + + NOT_FACE_ID + "%1" ne correspond à aucun ID valide d'une face du maillage. +Sélectionnez une face et essayez de nouveau + + + SOURCE + Source + + + TLT + Filtre de sélection + + + VOLUMES_TLT + Filtre de volumes + + + + SMESHGUI_FilterLibraryDlg + + ADD + Ajouter + + + ADD_TO_TLT + Ajouter le filtre de sélection à la librairie + + + ALL_FILES_FILTER + Tous les fichiers (*.*) + + + ASSIGN_NEW_NAME + La librairie déjà contient un filtre avec le nom "%1" +Le nouveau nom "%2" est attribué au filtre ajouté + + + COPY_FROM_TLT + Copier le filtre de la sélection de la librairie + + + DELETE + Supprimer + + + EDGE + Arête + + + EDIT_LIB_TLT + Librairie des filtres de sélection + + + ELEMENT + Elément + + + EMPTY_FILTER_NAME + Le nom du filtre est vide +Indiquez un nom non-vide + + + ERROR_FILTER_NAME + Le nom du filtre n'est pas unique +Indiquez un autre nom + + + ERROR_LOAD + Il est impossible de charger la librairie +Vérifiez le nom du fichier de la librairie et ses propriétés + + + ERROR_OF_ADDING + Une erreur interne s'est produite à l'addition d'un nouveau filtre dans la librairie. +Vérifiez la validité des informations données + + + ERROR_OF_COPYING + Une erreur interne s'est produite à la copie d'un filtre depuis la librairie. +Vérifiez la validité des informations données + + + ERROR_OF_DELETING + Une erreur interne s'est produite lors de la suppression d'un filtre depuis la librairie. +Vérifiez la validité des informations données + + + ERROR_OF_EDITING + Une erreur interne s'est produite à l'édition d'un filtre dans la librairie. +Vérifiez la validité des informations données + + + ERROR_OF_SAVING + Une erreur s'est produite à la sauvegarde de la librairie des filtres. +Vérifiez la validité des informations données + + + FACE + Face + + + FILTER + Filtre + + + FILTER_NAME + Nom du filtre + + + FILTER_NAMES + Noms des filtres + + + LIBRARY_FILE + Nom du fichier de librairie + + + LIBRARY_IS_NOT_LOADED + La librairie n'est pas ouverte. Ouvrez la librairie et essayez de nouveau + + + LIB_NAME + FilterLib.xml + + + NODE + Noeud + + + NO_PERMISSION + Vous n'avez pas la permission d'écrire dans ce fichier + + + OPEN_LIBRARY + Ouvrir la librairie + + + SELECTION + Sélection + + + VOLUME + Volume + + + XML_FILT + Fichiers XML (*.xml) + + + + SMESHGUI_FilterTable + + ADD + Ajouter + + + ADDITIONAL_PARAMETERS + Paramètres supplémentaires + + + ADD_TO + Ajouter à... + + + AND + Et + + + AREA + Aire + + + ASPECT_RATIO + Rapport de forme + + + ASPECT_RATIO_3D + Rapport de forme 3D + + + BAD_ORIENTED_VOLUME + Volume mal orienté + + + BELONG_TO_CYLINDER + Appartient au cylindre + + + BELONG_TO_GENSURFACE + Appartient à la surface + + + BELONG_TO_GEOM + Appartient à la géométrie + + + BELONG_TO_PLANE + Appartient au plan + + + BINARY + Opérateur logique + + + CLEAR + Effacer + + + COMPARE + Comparer + + + COPLANAR_FACES + Faces coplanaires + + + COPY_FROM + Copier de... + + + CRITERION + Critère + + + EDGES + Arêtes + + + ENTITY_TYPE + Type de l'entité + + + EQUAL_TO + Egal à + + + ERROR + La valeur du seuil n'est pas valide. Entrez une valeur correcte et essayez de nouveau + + + FACES + Faces + + + FILTER + Filtre + + + FREE_BORDERS + Bords libres + + + FREE_EDGES + Arêtes libres + + + FREE_NODES + Nœuds isolés + + + FREE_FACES + Faces libres + + + ID + ID + + + INSERT + Insérer + + + LENGTH + Longueur + + + LENGTH2D + Longueur 2D + + + LESS_THAN + Inférieur à ... + + + LYING_ON_GEOM + Repose sur la géométrie + + + MINIMUM_ANGLE + Angle minimal + + + MORE_THAN + Supérieur à ... + + + MULTIEDGES_ERROR + La valeur de seuil des bords multi-connectés ne peut pas être égal à 1 +Entrez une valeur correcte et essayez de nouveau + + + GROUPCOLOR_ERROR + Impossible d'identifier la couleur du groupe +Entrez une valeur correcte et essayez de nouveau + + + MULTI_BORDERS + Bords multi-connectés + + + NODES + Nœuds + + + NOT + Non + + + OR + Ou + + + RANGE_OF_IDS + Liste d'IDs + + + REMOVE + Supprimer + + + SKEW + Inclinaison + + + TAPER + Cône + + + THRESHOLD_VALUE + Valeur du seuil + + + UNARY + Négation + + + VOLUMES + Volumes + + + VOLUME_3D + Volume + + + WARPING + Déformation + + + LINEAR + Linéaire + + + GROUP_COLOR + Couleur du groupe + + + ELEMENTS + Eléments + + + GEOM_TYPE + Type de géométrie + + + GEOM_TYPE_0 + Point + + + GEOM_TYPE_1 + Arête + + + GEOM_TYPE_2 + Triangle + + + GEOM_TYPE_3 + Quadrangle + + + GEOM_TYPE_4 + Polygone + + + GEOM_TYPE_5 + Tétraèdre + + + GEOM_TYPE_6 + Pyramide + + + GEOM_TYPE_7 + Hexaèdre + + + GEOM_TYPE_8 + Pentaèdre + + + GEOM_TYPE_9 + Polyèdres + + + + SMESHGUI_GroupOpDlg + + ARGUMENTS + Arguments + + + DIFF_MESHES + Les arguments de l'opération ne sont pas indiqués correctement +Les groupes correspondent à des maillages différents +Donnez des arguments valides et essayez de nouveau + + + DIFF_TYPES + Les arguments de l'opération ne sont pas indiqués correctement +Les groupes contiennent des éléments de types différents +Donnez des arguments valides et essayez de nouveau + + + EMPTY_NAME + Le nom du groupe est invalide +Indiquez un nom non-vide et essayez de nouveau + + + INCORRECT_ARGUMENTS + Les arguments de l'opération ne sont pas indiqués +Indiquez-les et essayez de nouveau + + + NAME + Nom + + + OBJECT_1 + Objet 1 + + + OBJECT_2 + Objet 2 + + + RESULT_NAME + Nom du résultat + + + TOOL_OBJECT + Outil + + + UNION_OF_TWO_GROUPS + Union de deux groupes + + + + SMESHGUI_GroupDlg + + SELECT_ALL + Sélectionner tout + + + + SMESHGUI_UnionGroupsDlg + + UNION_OF_GROUPS + Union de groupes + + + + SMESHGUI_DimGroupDlg + + CREATE_GROUP_OF_UNDERLYING_ELEMS + Créer un groupe d'entités sous-jacentes + + + ELEMENTS_TYPE + Type d'éléments + + + NODE + Noeud + + + EDGE + Arête + + + FACE + Face + + + VOLUME + Volume + + + + SMESHGUI_IntersectGroupsDlg + + INTERSECTION_OF_GROUPS + Intersection de groupes + + + + SMESHGUI_CutGroupsDlg + + CUT_OF_GROUPS + Différence de groupes + + + MAIN_OBJECT + Objet principal + + + TOOL_OBJECT + Objet outil + + + + SMESHGUI_MakeNodeAtPointDlg + + AUTO_SEARCH + Trouver le noeud le plus proche de la destination + + + CAPTION + Déplacer un noeud + + + DESTINATION + Destination + + + MOVE_NODE + Déplacer un noeud + + + METHOD + Méthode + + + NODE_2MOVE + Noeud à déplacer + + + NODE_2MOVE_ID + ID + + + + SMESHGUI_MakeNodeAtPointOp + + INVALID_ID + L'ID du noeud est invalide + + + INVALID_MESH + Le maillage à modifier n'est pas sélectionné + + + + SMESHGUI_FindElemByPointDlg + + CAPTION + Trouver un élément par un point + + + CREATE_NEW_METHOD + Créer un noeud + + + MESH_PASS_THROUGH_POINT + Créer un noeud au point + + + METHOD + Méthode + + + MOVE_EXISTING_METHOD + Déplacer un noeud + + + NODE_2MOVE + Noeud à déplacer + + + NODE_2MOVE_ID + ID + + + + SMESHGUI_MeshDlg + + CREATE_MESH + Créer un maillage + + + CREATE_SUBMESH + Créer un sous-maillage + + + DIM_0D + 0D + + + DIM_1D + 1D + + + DIM_2D + 2D + + + DIM_3D + 3D + + + EDIT_MESH_SUBMESH + Editer un maillage/sous-maillage + + + GEOMETRY + Géométrie + + + HYPOTHESES_SETS + Attribuer un jeu d'hypothèses + + + MESH + Maillage + + + NAME + Nom + + + + SMESHGUI_MeshOp + + ALGORITHM_WITHOUT_HYPOTHESIS + L'algorithm pour la dimension %1 est défini mais l'hypothèse ne l'est pas + + + EDIT_SUBMESH_QUESTION + Un sous-maillage existe déjà sur la géométrie choisie +Voulez-vous éditer ce sous-maillage? + + + SUBMESH_NOT_ALLOWED + Créer un sous-maillage ignoré par l'algorithme global n'a pas de sens "%1" + + + GEOMETRY_OBJECT_IS_NOT_DEFINED + L'objet géométrique n'est pas défini +Indiquez-le et essayez de nouveau + + + GEOMETRY_OBJECT_IS_NULL + L'objet géométrique est nul + + + HYPOTHESES_AND_ALGORITHMS_ARE_NOT_DEFINED + Les hypothèses et les algorithmes ne sont pas définis + + + HYPOTHESIS_WITHOUT_ALGORITHM + L'hypothèse est définie pour la dimension %1 mais l'algorithme n'est pas défini + + + IMPORTED_MESH + Le maillage n'est pas construit sur une géométrie + + + INVALID_SUBSHAPE + L'objet géométrique n'est pas un sous-objet de l'objet maillé + + + MESH_IS_NOT_DEFINED + Le maillage n'est pas défini +Spécifiez-le et essayez de nouveau + + + MESH_IS_NULL + Le maillage est nul + + + NAME_OF_MESH_IS_EMPTY + Le nom du maillage est vide +Indiquez un nom valide et essayez de nouveau + + + NAME_OF_SUBMESH_IS_EMPTY + Le nom du sous-maillage est vide +Indiquez un nom valide et essayez de nouveau + + + THERE_IS_NO_OBJECT_FOR_EDITING + Il n'y a pas d'objet à éditer. +Sélectionnez un maillage ou un sous-maillage et essayez de nouveau + + + + SMESHGUI_MeshPatternDlg + + 3D_BLOCK + Bloc 3D + + + CAPTION + Projection de motif + + + CREATE_POLYEDRS_NEAR_BOUNDARY + Créer des polyèdres près de la frontière + + + CREATE_POLYGONS_NEAR_BOUNDARY + Créer des polygones près de la frontière + + + ERROR_OF_LOADING + Impossible de charger le motif. +Il est probable que le fichier est corrompu ou contient un autre type de motif + + + ERROR_OF_OPENING + Il est impossible d'ouvrir le fichier. +Vérifiez s'il existe et si vous avez l'autorisation + + + ERROR_OF_READING + Il est impossible de charger le motif +Vérifiez le contenu du fichier + + + ERR_READ_3D_COORD + Il est impossible de charger le motif +Les coordonnées des points 3D sont en dehors de l'intervalle [0,1] + + + ERR_READ_BAD_INDEX + Il est impossible de charger le motif +Un index de point invalide a été detecté + + + ERR_READ_BAD_KEY_POINT + Il est impossible de charger le motif +Le point-clef n'est pas situé sur la frontière + + + ERR_READ_ELEM_POINTS + Il est impossible de charger le motif +Le nombre de points de l'élément est invalide + + + ERR_READ_NB_POINTS + Il est impossible de charger le motif +Il est impossible de lire le nombre de points dans le fichier + + + ERR_READ_NO_ELEMS + Il est impossible de charger le motif +Il ne contient pas d'éléments + + + ERR_READ_NO_KEYPOINT + Il est impossible de charger le motif +Le motif 2D n'a pas de point-clef + + + ERR_READ_POINT_COORDS + Il est impossible de charger le motif +Il est impossible de lire les coordonnées des points dans le fichier + + + ERR_READ_TOO_FEW_POINTS + Il est impossible de charger le motif. +Il y a trop peu de points dans le fichier + + + FACE + Face + + + LOAD_PATTERN + Charger un motif + + + MESH_FACES + Faces du maillage + + + MESH_VOLUMES + Volumes du maillage + + + NEW + Nouveau... + + + NODE_1 + Noeud 1 + + + NODE_2 + Noeud 2 + + + PATTERN + Motif + + + PATTERN_FILT + Fichiers de motif (*.smp) + + + PATTERN_TYPE + Type de motif + + + PREVIEW + Prévisualiser + + + REFINE + Raffiner les éléments de maillage sélectionnés + + + REVERSE + Inverser l'ordre des points-clefs + + + VERTEX + Sommet... + + + VERTEX1 + Sommet 1 + + + VERTEX2 + Sommet 2 + + + + SMESHGUI_MeshTab + + ADD_HYPOTHESIS + Ajouter l'hypothèse + + + ALGORITHM + Algorithme + + + HYPOTHESIS + Hypothèse + + + NONE + <None> + + + + SMESHGUI_MultiEditDlg + + ADD + Ajouter + + + FILTER + Filtre + + + REMOVE + Supprimer + + + SELECT_FROM + Sélectionner à partir de + + + SORT_LIST + Trier la liste + + + SPLIT_JOIN_CRITERION + Critère + + + TO_ALL + Appliquer à tous + + + USE_DIAGONAL_1_3 + Utiliser la diagonale 1-3 + + + USE_DIAGONAL_2_4 + Utiliser la diagonale 2-4 + + + USE_NUMERIC_FUNC + Utiliser le facteur numérique + + + + SMESHGUI_CuttingIntoTetraDlg + + CAPTION + Diviser les volumes en tétraèdres + + + SPLIT_METHOD + Diviser l'héxaèdre + + + SPLIT_HEX_TO_5_TETRA + En 5 tétraèdres + + + SPLIT_HEX_TO_6_TETRA + En 6 tétraèdres + + + SPLIT_HEX_TO_24_TETRA + En 24 tétraèdres + + + + SMESHGUI_PrecisionDlg + + CAPTION + Précision pour les contrôles de qualité du maillage + + + NOT_USE + Ne pas utiliser! + + + PRECISION + Nombre de chiffres après la virgule + + + + SMESHGUI_RevolutionDlg + + ANGLE_BY_STEP + Angle par pas + + + PREVIEW + Prévisualiser + + + REVOLUTION_1D + Révolution des éléments 1D + + + REVOLUTION_2D + Révolution des éléments 2D + + + REVOLUTION_AROUND_AXIS + Révolution autour d'un axe + + + TOTAL_ANGLE + Angle total + + + MEN_POINT_SELECT + De l'origine au point sélectionner + + + MEN_FACE_SELECT + Normale de la face sélectionnée + + + + SMESHGUI_SewingDlg + + BORDER + Frontière + + + BORDER_1 + Frontière 1 + + + BORDER_2 + Frontière 2 + + + CREATE_POLYEDRS_NEAR_BOUNDARY + Remplacer les volumes concernés par des polyèdres + + + CREATE_POLYGONS_INSTEAD_SPLITTING + Créer des polygones au lieu de redécouper + + + ERROR_1 + La frontière Libre1 n'est pas trouvée avec les nœuds sélectionnés + + + ERROR_2 + La frontière Libre2 n'est pas trouvée avec les nœuds sélectionnés + + + ERROR_3 + Les frontières Libres 1 et 2 n'ont pas été trouvées avec les nœuds sélectionnés + + + ERROR_4 + Aucun chemin du premier au dernier noeud de la frontière n'est trouvé + + + ERROR_5 + Il n'est pas permis de découper les volumes de bord! + + + ERROR_6 + Le nombre d'éléments sélectionnés est différent de chaque côté + + + ERROR_7 + Les jeux d'éléments sont topologiquement différents ou les nœuds ne conviennent pas + + + ERROR_8 + Les nœuds du côté 1 soit ne sont pas connectés soit ne sont pas situés à la frontière du jeu d'éléments + + + ERROR_9 + Les nœuds du côté 2 soit ne sont pas connectés soit ne sont pas situés à la frontière de l'élément + + + FIRST_NODE_ID + ID du premier noeud + + + LAST_NODE_ID + ID du dernier noeud + + + MERGE_EQUAL_ELEMENTS + Fusionner les éléments égaux + + + NODE1_TO_MERGE + Noeud 1 à fusionner + + + NODE2_TO_MERGE + Noeud 2 à fusionner + + + SECOND_NODE_ID + ID du deuxième noeud + + + SEW_BORDER_TO_SIDE + Coudre la frontière au côté + + + SEW_CONFORM_FREE_BORDERS + Coudre les frontières libres conformes + + + SEW_FREE_BORDERS + Coudre les frontières libres + + + SEW_SIDE_ELEMENTS + Coudre les éléments de bord + + + SIDE + Bord + + + SIDE_1 + Bord 1 + + + SIDE_2 + Bord 2 + + + + SMESHGUI_ShapeByMeshDlg + + CAPTION + Trouver la géométrie par le maillage + + + + SMESHGUI_SingleEditDlg + + EDGE_BETWEEN + Arête entre des triangles voisins + + + + SMESHGUI_SmoothingDlg + + CENTROIDAL + Centroïdal + + + FIXED_NODES_IDS + IDs des nœuds fixes + + + IS_PARAMETRIC + dans l'espace paramétrique + + + ITERATION_LIMIT + Limite d'Itération + + + LAPLACIAN + Laplacien + + + MAX_ASPECT_RATIO + Rapport de forme maximal + + + METHOD + Méthode + + + + SMESHGUI_TrianglesInversionDlg + + CAPTION + Inversion de diagonale + + + + SMESHGUI_UnionOfTrianglesDlg + + CAPTION + Union des triangles + + + MAXIMUM_ANGLE + Angle maximal de pliage + + + + SMESHGUI_UnionOfTwoTrianglesDlg + + CAPTION + Union de deux triangles + + + + SMESHGUI_WhatIsDlg + + ENTITY_TYPE + Type d'élément + + + GRAVITY_CENTER + Centre de Gravité + + + CONNECTED_ELEMENTS + Connecté avec d'Eléments + + + + SMESHGUI_FileInfoDlg + + CAPTION + Informations sur le fichier + + + FILE_NAME + Nom du fichier + + + FILE_SIZE + Taille du fichier (bytes) + + + MED_VERSION + Version MED + + + + SMESHGUI_GroupOnShapeDlg + + SMESH_CREATE_GROUP_FROM_GEOM + Créer des groupes à partir de la géométrie + + + + SMESHGUI_MeshOrderDlg + + SMESH_MESHORDER_TITLE + Ordre des sous-maillages dans la procédure de maillage + + + + SMESHGUI_MeshOrderOp + + SMESH_NO_CONCURENT_MESH + Pas de sous-maillages concurrents détectés + + + + SMESHGUI_ClippingDlg + + CLIP_PLANES + Plans de découpe + + + ROTATION_AROUND_X_Y2Z + Rotation autour de X (Y à Z): + + + ROTATION_AROUND_Y_X2Z + Rotation autour de Y (X à Z): + + + ROTATION_AROUND_Z_Y2X + Rotation autour de Z (Y à X): + + + ROTATION_AROUND_X_Z2Y + Rotation autour de X (Z à Y): + + + ROTATION_AROUND_Y_Z2X + Rotation autour de Y (Z à X): + + + ROTATION_AROUND_Z_X2Y + Rotation autour de Z (X à Y): + + + SHOW_PREVIEW + Prévisualiser + + + AUTO_APPLY + Appliquer automatiquement + + + ALONG_XY + || X-Y + + + ALONG_YZ + || Y-Z + + + ALONG_ZX + || Z-X + + + PLANE_NUM + Plan# %1 + + + NO_PLANES + Pas de plans + + + + SMESHGUI_DuplicateNodesDlg + + DUPLICATION_MODE + Mode de duplication + + + DUPLICATION_WITHOUT_ELEMS + Sans duplication des éléments de frontière + + + GROUP_NODES_TO_DUPLICATE + Groupe des nœuds à dupliquer + + + GROUP_NODES_TO_REPLACE + Groupe des éléments dont les nœuds sont à remplacer + + + DUPLICATION_WITH_ELEMS + Avec duplication des éléments de frontière + + + GROUP_ELEMS_TO_DUPLICATE + Groupe des éléments à dupliquer + + + GROUP_NODES_NOT_DUPLICATE + Groupe des nœuds à ne pas dupliquer + + + GROUP_ELEMS_TO_REPLACE + Groupe des éléments dont les nœuds sont à remplacer + + + CONSTRUCT_NEW_GROUP_NODES + Construire un groupe avec les nœuds nouvellement créés + + + CONSTRUCT_NEW_GROUP_ELEMENTS + Construire un groupe avec les éléments nouvellement créés + + + + SMESHGUI_Make2DFrom3DDlg + + CAPTION + Créer les éléments de frontière + + + MESH + Maillage, sous-maillage ou groupe + + + MODE + Mode + + + 2D_FROM_3D + 2D à partir de 3D + + + 1D_FROM_3D + 1D à partir de 3D + + + 1D_FROM_2D + 1D à partir de 2D + + + TARGET + Cible + + + THIS_MESH + Ce maillage + + + NEW_MESH + Nouveau maillage + + + COPY_SRC + Copier le maillage source + + + MISSING_ONLY + Copier seulement les éléments manquants + + + CREATE_GROUP + Créer un groupe + + + + SMESHGUI_Make2DFrom3DOp + + SMESH_ERR_NO_INPUT_MESH + Aucun maillage, sous-maillage ou groupe source n'est indiqué + + + SMESH_ERR_NO_3D_ELEMENTS + L'objet source ne contient pas d'éléments 3D + + + SMESH_ERR_NO_2D_ELEMENTS + L'objet source ne contient pas d'éléments 2D + + + SMESH_ERR_MESH_NAME_NOT_SPECIFIED + Le nom du nouveau maillage n'est pas indiqué + + + SMESH_ERR_GRP_NAME_NOT_SPECIFIED + Le nom du groupe n'est pas indiqué + + + diff --git a/src/SMESH_I/Makefile.am b/src/SMESH_I/Makefile.am index 9a2a3c6a4..53f285528 100644 --- a/src/SMESH_I/Makefile.am +++ b/src/SMESH_I/Makefile.am @@ -46,6 +46,7 @@ salomeinclude_HEADERS = \ SMESH_Pattern_i.hxx \ SMESH_2smeshpy.hxx \ SMESH_NoteBook.hxx \ + SMESH_Measurements_i.hxx \ SMESH.hxx # Scripts to be installed. @@ -76,7 +77,8 @@ dist_libSMESHEngine_la_SOURCES = \ SMESH_Group_i.cxx \ SMESH_Pattern_i.cxx \ SMESH_2smeshpy.cxx \ - SMESH_NoteBook.cxx + SMESH_NoteBook.cxx \ + SMESH_Measurements_i.cxx # Executables targets bin_PROGRAMS = SMESHEngine diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index 640f51191..dfb378f24 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -342,6 +342,7 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand ) // Concatenate( [mesh1, ...], ... ) // CreateHypothesis( theHypType, theLibName ) // Compute( mesh, geom ) + // Evaluate( mesh, geom ) // mesh creation TCollection_AsciiString method = theCommand->GetMethod(); @@ -395,6 +396,20 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand ) } } + // smeshgen.Evaluate( mesh, geom ) --> mesh.Evaluate(geom) + if ( method == "Evaluate" ) + { + const _pyID& meshID = theCommand->GetArg( 1 ); + map< _pyID, Handle(_pyMesh) >::iterator id_mesh = myMeshes.find( meshID ); + if ( id_mesh != myMeshes.end() ) { + theCommand->SetObject( meshID ); + _pyID geom = theCommand->GetArg( 2 ); + theCommand->RemoveArgs(); + theCommand->SetArg( 1, geom ); + return; + } + } + // objects erasing creation command if no more it's commands invoked: // SMESH_Pattern, FilterManager if ( method == "GetPattern" || method == "CreateFilterManager" ) { @@ -1091,12 +1106,12 @@ _pyMeshEditor::_pyMeshEditor(const Handle(_pyCommand)& theCreationCmd): void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand) { - // names of SMESH_MeshEditor methods fully equal to methods of class Mesh, so + // names of SMESH_MeshEditor methods fully equal to methods of python class Mesh, so // commands calling this methods are converted to calls of methods of Mesh static TStringSet sameMethods; if ( sameMethods.empty() ) { const char * names[] = { - "RemoveElements","RemoveNodes","AddNode","Add0DElement","AddEdge","AddFace","AddPolygonalFace", + "RemoveElements","RemoveNodes","RemoveOrphanNodes","AddNode","Add0DElement","AddEdge","AddFace","AddPolygonalFace", "AddVolume","AddPolyhedralVolume","AddPolyhedralVolumeByFaces","MoveNode", "MoveClosestNodeToPoint", "InverseDiag","DeleteDiag","Reorient","ReorientObject","TriToQuad","SplitQuad","SplitQuadObject", "BestSplit","Smooth","SmoothObject","SmoothParametric","SmoothParametricObject", @@ -1105,7 +1120,7 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand) "ExtrusionSweep","AdvancedExtrusion","ExtrusionSweepObject","ExtrusionSweepObject1D","ExtrusionSweepObject2D", "ExtrusionAlongPath","ExtrusionAlongPathObject","ExtrusionAlongPathObject1D","ExtrusionAlongPathObject2D", "Mirror","MirrorObject","Translate","TranslateObject","Rotate","RotateObject", - "FindCoincidentNodes","FindCoincidentNodesOnPart","MergeNodes","FindEqualElements", + "FindCoincidentNodes",/*"FindCoincidentNodesOnPart",*/"MergeNodes","FindEqualElements", "MergeElements","MergeEqualElements","SewFreeBorders","SewConformFreeBorders", "SewBorderToSide","SewSideElements","ChangeElemNodes","GetLastCreatedNodes", "GetLastCreatedElems", @@ -1116,9 +1131,9 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand) } // names of SMESH_MeshEditor methods which differ from methods of class Mesh - // only last two arguments + // only by last two arguments static TStringSet diffLastTwoArgsMethods; - if (diffLastTwoArgsMethods.empty() ){ + if (diffLastTwoArgsMethods.empty() ) { const char * names[] = { "MirrorMakeGroups","MirrorObjectMakeGroups", "TranslateMakeGroups","TranslateObjectMakeGroups", @@ -1127,41 +1142,59 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand) diffLastTwoArgsMethods.Insert( names ); } - if ( sameMethods.Contains( theCommand->GetMethod() )) { - theCommand->SetObject( myMesh ); - - // meshes made by *MakeMesh() methods are not wrapped by _pyMesh, - // so let _pyMesh care of it (TMP?) -// if ( theCommand->GetMethod().Search("MakeMesh") != -1 ) -// _pyMesh( new _pyCommand( theCommand->GetString(), 0 )); // for theGen->SetAccessorMethod() - } - else { - + const TCollection_AsciiString & method = theCommand->GetMethod(); + bool isPyMeshMethod = sameMethods.Contains( method ); + if ( !isPyMeshMethod ) + { //Replace SMESH_MeshEditor "MakeGroups" functions on the Mesh //functions with the flag "theMakeGroups = True" like: //SMESH_MeshEditor.CmdMakeGroups => Mesh.Cmd(...,True) - int pos = theCommand->GetMethod().Search("MakeGroups"); - if( pos != -1) { + int pos = method.Search("MakeGroups"); + if( pos != -1) + { + isPyMeshMethod = true; + // 1. Remove "MakeGroups" from the Command TCollection_AsciiString aMethod = theCommand->GetMethod(); int nbArgsToAdd = diffLastTwoArgsMethods.Contains(aMethod) ? 2 : 1; aMethod.Trunc(pos-1); theCommand->SetMethod(aMethod); - // 2. Set Mesh object instead of SMESH_MeshEditor - theCommand->SetObject( myMesh ); - - // 3. And add last "True" argument + // 2. And add last "True" argument(s) while(nbArgsToAdd--) - theCommand->SetArg(theCommand->GetNbArgs()+1,"True "); + theCommand->SetArg(theCommand->GetNbArgs()+1,"True"); } - else { - // editor creation command is needed only if any editor function is called - theGen->AddMeshAccessorMethod( theCommand ); // for *Object() - if ( !myCreationCmdStr.IsEmpty() ) { - GetCreationCmd()->GetString() = myCreationCmdStr; - myCreationCmdStr.Clear(); - } + } + + // set "FindCoincidentNodesOnPart()" instead of "FindCoincidentNodesOnPartBut()" + if ( !isPyMeshMethod && method == "FindCoincidentNodesOnPartBut") + { + isPyMeshMethod=true; + theCommand->SetMethod("FindCoincidentNodesOnPart"); + } + // DoubleNodeElemGroupNew() -> DoubleNodeElemGroup() + if ( !isPyMeshMethod && ( method == "DoubleNodeElemGroupNew" || method == "DoubleNodeGroupNew")) + { + isPyMeshMethod=true; + theCommand->SetMethod( method.SubString( 1, method.Length()-3)); + theCommand->SetArg(theCommand->GetNbArgs()+1,"True"); + } + + // meshes made by *MakeMesh() methods are not wrapped by _pyMesh, + // so let _pyMesh care of it (TMP?) + // if ( theCommand->GetMethod().Search("MakeMesh") != -1 ) + // _pyMesh( new _pyCommand( theCommand->GetString(), 0 )); // for theGen->SetAccessorMethod() + if ( isPyMeshMethod ) + { + theCommand->SetObject( myMesh ); + } + else + { + // editor creation command is needed only if any editor function is called + theGen->AddMeshAccessorMethod( theCommand ); // for *Object() + if ( !myCreationCmdStr.IsEmpty() ) { + GetCreationCmd()->GetString() = myCreationCmdStr; + myCreationCmdStr.Clear(); } } } diff --git a/src/SMESH_I/SMESH_DumpPython.cxx b/src/SMESH_I/SMESH_DumpPython.cxx index 5be4f5de4..3fd8ff22f 100644 --- a/src/SMESH_I/SMESH_DumpPython.cxx +++ b/src/SMESH_I/SMESH_DumpPython.cxx @@ -152,7 +152,7 @@ namespace SMESH } template - void DumpArray(const TArray& theArray, std::ostringstream & theStream) + void DumpArray(const TArray& theArray, TPythonDump & theStream) { theStream << "[ "; for (int i = 1; i <= theArray.length(); i++) { @@ -166,14 +166,14 @@ namespace SMESH TPythonDump& TPythonDump::operator<<(const SMESH::long_array& theArg) { - DumpArray( theArg, myStream ); + DumpArray( theArg, *this ); return *this; } TPythonDump& TPythonDump::operator<<(const SMESH::double_array& theArg) { - DumpArray( theArg, myStream ); + DumpArray( theArg, *this ); return *this; } @@ -274,6 +274,8 @@ namespace SMESH case FT_Skew: myStream<< "aSkew"; break; case FT_Area: myStream<< "aArea"; break; case FT_Volume3D: myStream<< "aVolume3D"; break; + case FT_MaxElementLength2D:myStream<< "aMaxElementLength2D";break; + case FT_MaxElementLength3D:myStream<< "aMaxElementLength3D";break; case FT_FreeBorders: myStream<< "aFreeBorders"; break; case FT_FreeEdges: myStream<< "aFreeEdges"; break; case FT_FreeNodes: myStream<< "aFreeNodes"; break; @@ -287,6 +289,7 @@ namespace SMESH case FT_BelongToCylinder: myStream<< "aBelongToCylinder"; break; case FT_BelongToGenSurface:myStream<<"aBelongToGenSurface";break; case FT_LyingOnGeom: myStream<< "aLyingOnGeom"; break; + case FT_CoplanarFaces: myStream<< "aCoplanarFaces"; break; case FT_RangeOfIds: myStream<< "aRangeOfIds"; break; case FT_BadOrientedVolume:myStream<< "aBadOrientedVolume";break; case FT_LinearOrQuadratic:myStream<< "aLinearOrQuadratic";break; @@ -306,6 +309,15 @@ namespace SMESH return *this; } + TPythonDump& + TPythonDump:: + operator<<(SMESH::Measurements_i* theArg) + { + myStream<<"aMeasurements"; + return *this; + } + + TPythonDump& TPythonDump:: operator<<(SMESH_Gen_i* theArg) { myStream << SMESHGenName(); return *this; @@ -354,21 +366,14 @@ namespace SMESH return *this; } - TPythonDump& TPythonDump::operator<<(const SMESH::ListOfGroups * theList){ - if(theList && theList->length() > 0 ) { - SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen(); - SALOMEDS::Study_ptr aStudy = aSMESHGen->GetCurrentStudy(); - myStream << "["; - int aListLen = theList->length(); - for(int i = 0 ; i < aListLen; i++){ - SALOMEDS::SObject_var aSObject = SMESH_Gen_i::ObjectToSObject(aStudy,(*theList)[i]); - if(!aSObject->_is_nil()) { - myStream << aSObject->GetID(); - i < (aListLen - 1) ? myStream<<", " : myStream<<"]"; - } - - } - } + TPythonDump& TPythonDump::operator<<(const SMESH::ListOfGroups& theList) + { + DumpArray( theList, *this ); + return *this; + } + TPythonDump& TPythonDump::operator<<(const SMESH::ListOfIDSources& theList) + { + DumpArray( theList, *this ); return *this; } @@ -377,10 +382,10 @@ namespace SMESH //================================================================================ /*! - * \brief Return marker of long string literal beginning - * \param type - a name of functionality producing the string literal - * \retval TCollection_AsciiString - the marker string to be written into - * a raw python script + * \brief Return marker of long string literal beginning + * \param type - a name of functionality producing the string literal + * \retval TCollection_AsciiString - the marker string to be written into + * a raw python script */ //================================================================================ @@ -690,6 +695,7 @@ TCollection_AsciiString SMESH_Gen_i::DumpPython_impl TCollection_AsciiString aScript; aScript = "def RebuildData(theStudy):\n\t"; aScript += helper + "aFilterManager = " + aSMESHGen + ".CreateFilterManager()\n\t"; + aScript += helper + "aMeasurements = " + aSMESHGen + ".CreateMeasurements()\n\t"; if ( isPublished ) aScript += aSMESHGen + ".SetCurrentStudy(theStudy)"; else diff --git a/src/SMESH_I/SMESH_Filter_i.cxx b/src/SMESH_I/SMESH_Filter_i.cxx index 969ffb613..d2a7ae648 100644 --- a/src/SMESH_I/SMESH_Filter_i.cxx +++ b/src/SMESH_I/SMESH_Filter_i.cxx @@ -596,6 +596,28 @@ CORBA::Double NumericalFunctor_i::GetValue( CORBA::Long theId ) return myNumericalFunctorPtr->GetValue( theId ); } +SMESH::Histogram* NumericalFunctor_i::GetHistogram(CORBA::Short nbIntervals) +{ + std::vector nbEvents; + std::vector funValues; + myNumericalFunctorPtr->GetHistogram(nbIntervals,nbEvents,funValues); + + nbIntervals = CORBA::Short( std::min( nbEvents.size(), funValues.size() - 1)); + SMESH::Histogram_var histogram = new SMESH::Histogram; + if ( nbIntervals > 0 ) + { + histogram->length( nbIntervals ); + for ( int i = 0; i < nbIntervals; ++i ) + { + HistogramRectangle& rect = histogram[i]; + rect.nbEvents = nbEvents[i]; + rect.min = funValues[i]; + rect.max = funValues[i+1]; + } + } + return histogram._retn(); +} + void NumericalFunctor_i::SetPrecision( CORBA::Long thePrecision ) { myNumericalFunctorPtr->SetPrecision( thePrecision ); @@ -738,6 +760,36 @@ FunctorType Volume3D_i::GetFunctorType() return SMESH::FT_Volume3D; } +/* + Class : MaxElementLength2D_i + Description : Functor for calculating maximum length of 2D element +*/ +MaxElementLength2D_i::MaxElementLength2D_i() +{ + myNumericalFunctorPtr.reset( new Controls::MaxElementLength2D() ); + myFunctorPtr = myNumericalFunctorPtr; +} + +FunctorType MaxElementLength2D_i::GetFunctorType() +{ + return SMESH::FT_MaxElementLength2D; +} + +/* + Class : MaxElementLength3D_i + Description : Functor for calculating maximum length of 3D element +*/ +MaxElementLength3D_i::MaxElementLength3D_i() +{ + myNumericalFunctorPtr.reset( new Controls::MaxElementLength3D() ); + myFunctorPtr = myNumericalFunctorPtr; +} + +FunctorType MaxElementLength3D_i::GetFunctorType() +{ + return SMESH::FT_MaxElementLength3D; +} + /* Class : Length_i Description : Functor for calculating length off edge @@ -772,11 +824,12 @@ SMESH::Length2D::Values* Length2D_i::GetValues() { INFOS("Length2D_i::GetValues"); SMESH::Controls::Length2D::TValues aValues; - myLength2DPtr->GetValues( aValues ); + (dynamic_cast(myFunctorPtr.get()))->GetValues( aValues ); long i = 0, iEnd = aValues.size(); SMESH::Length2D::Values_var aResult = new SMESH::Length2D::Values(iEnd); + aResult->length(iEnd); SMESH::Controls::Length2D::TValues::const_iterator anIter; for ( anIter = aValues.begin() ; anIter != aValues.end(); anIter++, i++ ) @@ -827,11 +880,12 @@ SMESH::MultiConnection2D::Values* MultiConnection2D_i::GetValues() { INFOS("MultiConnection2D_i::GetValues"); SMESH::Controls::MultiConnection2D::MValues aValues; - myMulticonnection2DPtr->GetValues( aValues ); - + (dynamic_cast(myFunctorPtr.get()))->GetValues( aValues ); + long i = 0, iEnd = aValues.size(); SMESH::MultiConnection2D::Values_var aResult = new SMESH::MultiConnection2D::Values(iEnd); + aResult->length(iEnd); SMESH::Controls::MultiConnection2D::MValues::const_iterator anIter; for ( anIter = aValues.begin() ; anIter != aValues.end(); anIter++, i++ ) @@ -1441,7 +1495,7 @@ void ElemGeomType_i::SetGeometryType(GeometryType theType) GeometryType ElemGeomType_i::GetGeometryType() const { - return (GeometryType)myElemGeomTypePtr->GetGeomType();; + return (GeometryType)myElemGeomTypePtr->GetGeomType(); } FunctorType ElemGeomType_i::GetFunctorType() @@ -1449,6 +1503,49 @@ FunctorType ElemGeomType_i::GetFunctorType() return SMESH::FT_ElemGeomType; } +/* + Class : CoplanarFaces_i + Description : Returns true if a mesh face is a coplanar neighbour to a given one +*/ +CoplanarFaces_i::CoplanarFaces_i() +{ + myCoplanarFacesPtr.reset(new Controls::CoplanarFaces()); + myFunctorPtr = myPredicatePtr = myCoplanarFacesPtr; +} + +void CoplanarFaces_i::SetFace ( CORBA::Long theFaceID ) +{ + myCoplanarFacesPtr->SetFace(theFaceID); + TPythonDump()<SetTolerance(theToler); + TPythonDump()<GetFace(); +} + +char* CoplanarFaces_i::GetFaceAsString () const +{ + TCollection_AsciiString str(Standard_Integer(myCoplanarFacesPtr->GetFace())); + return CORBA::string_dup( str.ToCString() ); +} + +CORBA::Double CoplanarFaces_i::GetTolerance() const +{ + return myCoplanarFacesPtr->GetTolerance(); +} + +FunctorType CoplanarFaces_i::GetFunctorType() +{ + return SMESH::FT_CoplanarFaces; +} + /* Class : Comparator_i Description : Base class for comparators @@ -1793,6 +1890,24 @@ Volume3D_ptr FilterManager_i::CreateVolume3D() } +MaxElementLength2D_ptr FilterManager_i::CreateMaxElementLength2D() +{ + SMESH::MaxElementLength2D_i* aServant = new SMESH::MaxElementLength2D_i(); + SMESH::MaxElementLength2D_var anObj = aServant->_this(); + TPythonDump()<_this(); + TPythonDump()<_this(); + TPythonDump()<length( 1 ); + types[0] = GetElementType(); + return types._retn(); +} + +//======================================================================= +//function : GetMesh +//purpose : Returns mesh +//======================================================================= + +SMESH::SMESH_Mesh_ptr Filter_i::GetMesh() +{ + return SMESH_Mesh::_duplicate( myMesh ); +} + //======================================================================= // name : getCriteria // Purpose : Retrieve criterions from predicate @@ -2283,6 +2431,22 @@ static inline bool getCriteria( Predicate_i* thePred, theCriteria[ i ].TypeOfElement = aPred->GetElementType(); theCriteria[ i ].Tolerance = aPred->GetTolerance(); + return true; + } + case FT_CoplanarFaces: + { + CoplanarFaces_i* aPred = dynamic_cast( thePred ); + + CORBA::ULong i = theCriteria->length(); + theCriteria->length( i + 1 ); + + theCriteria[ i ] = createCriterion(); + CORBA::String_var faceId = aPred->GetFaceAsString(); + + theCriteria[ i ].Type = FT_CoplanarFaces; + theCriteria[ i ].ThresholdID = faceId; + theCriteria[ i ].Tolerance = aPred->GetTolerance(); + return true; } case FT_RangeOfIds: @@ -2489,6 +2653,12 @@ CORBA::Boolean Filter_i::SetCriteria( const SMESH::Filter::Criteria& theCriteria case SMESH::FT_Volume3D: aFunctor = aFilterMgr->CreateVolume3D(); break; + case SMESH::FT_MaxElementLength2D: + aFunctor = aFilterMgr->CreateMaxElementLength2D(); + break; + case SMESH::FT_MaxElementLength3D: + aFunctor = aFilterMgr->CreateMaxElementLength3D(); + break; // Predicates @@ -2576,6 +2746,14 @@ CORBA::Boolean Filter_i::SetCriteria( const SMESH::Filter::Criteria& theCriteria aPredicate = tmpPred; break; } + case SMESH::FT_CoplanarFaces: + { + SMESH::CoplanarFaces_ptr tmpPred = aFilterMgr->CreateCoplanarFaces(); + tmpPred->SetFace( atol (aThresholdID )); + tmpPred->SetTolerance( aTolerance ); + aPredicate = tmpPred; + break; + } default: continue; @@ -2778,6 +2956,8 @@ static inline LDOMString toString( CORBA::Long theType ) case FT_Skew : return "Skew"; case FT_Area : return "Area"; case FT_Volume3D : return "Volume3D"; + case FT_MaxElementLength2D: return "Max element length 2D"; + case FT_MaxElementLength3D: return "Max element length 3D"; case FT_BelongToGeom : return "Belong to Geom"; case FT_BelongToPlane : return "Belong to Plane"; case FT_BelongToCylinder: return "Belong to Cylinder"; @@ -2820,6 +3000,8 @@ static inline SMESH::FunctorType toFunctorType( const LDOMString& theStr ) else if ( theStr.equals( "Skew" ) ) return FT_Skew; else if ( theStr.equals( "Area" ) ) return FT_Area; else if ( theStr.equals( "Volume3D" ) ) return FT_Volume3D; + else if ( theStr.equals( "Max element length 2D" ) ) return FT_MaxElementLength2D; + else if ( theStr.equals( "Max element length 3D" ) ) return FT_MaxElementLength3D; else if ( theStr.equals( "Belong to Geom" ) ) return FT_BelongToGeom; else if ( theStr.equals( "Belong to Plane" ) ) return FT_BelongToPlane; else if ( theStr.equals( "Belong to Cylinder" ) ) return FT_BelongToCylinder; diff --git a/src/SMESH_I/SMESH_Filter_i.hxx b/src/SMESH_I/SMESH_Filter_i.hxx index 057c7693b..bef8c2252 100644 --- a/src/SMESH_I/SMESH_Filter_i.hxx +++ b/src/SMESH_I/SMESH_Filter_i.hxx @@ -157,6 +157,7 @@ namespace SMESH { public: CORBA::Double GetValue( CORBA::Long theElementId ); + SMESH::Histogram* GetHistogram(CORBA::Short nbIntervals); void SetPrecision( CORBA::Long thePrecision ); CORBA::Long GetPrecision(); Controls::NumericalFunctorPtr GetNumericalFunctor(); @@ -270,6 +271,32 @@ namespace SMESH }; + /* + Class : MaxElementLength2D_i + Description : Functor for calculating maximum length of 2D element + */ + class SMESH_I_EXPORT MaxElementLength2D_i: public virtual POA_SMESH::MaxElementLength2D, + public virtual NumericalFunctor_i + { + public: + MaxElementLength2D_i(); + FunctorType GetFunctorType(); + }; + + + /* + Class : MaxElementLength3D_i + Description : Functor for calculating maximum length of 3D element + */ + class SMESH_I_EXPORT MaxElementLength3D_i: public virtual POA_SMESH::MaxElementLength3D, + public virtual NumericalFunctor_i + { + public: + MaxElementLength3D_i(); + FunctorType GetFunctorType(); + }; + + /* Class : Length_i Description : Functor for calculating length of edge @@ -622,6 +649,26 @@ namespace SMESH Controls::ElemGeomTypePtr myElemGeomTypePtr; }; + /* + Class : CoplanarFaces_i + Description : Returns true if a mesh face is a coplanar neighbour to a given one + */ + class SMESH_I_EXPORT CoplanarFaces_i: public virtual POA_SMESH::CoplanarFaces, + public virtual Predicate_i + { + public: + CoplanarFaces_i(); + FunctorType GetFunctorType(); + + void SetFace ( CORBA::Long theFaceID ); + void SetTolerance( CORBA::Double theToler ); + char* GetFaceAsString () const; + CORBA::Long GetFace () const; + CORBA::Double GetTolerance () const; + private: + Controls::CoplanarFacesPtr myCoplanarFacesPtr; + }; + /* Class : Comparator_i Description : Base class for comparators @@ -782,14 +829,6 @@ namespace SMESH void SetMesh( SMESH_Mesh_ptr ); - virtual - SMESH::long_array* - GetIDs(); - - virtual - SMESH::long_array* - GetMeshInfo(); - static void GetElementsId( Predicate_i*, @@ -823,6 +862,14 @@ namespace SMESH Predicate_i* GetPredicate_i(); + // ========================= + // SMESH_IDSource interface + // ========================= + virtual SMESH::long_array* GetIDs(); + virtual SMESH::long_array* GetMeshInfo(); + virtual SMESH::array_of_ElementType* GetTypes(); + virtual SMESH::SMESH_Mesh_ptr GetMesh(); + private: Controls::Filter myFilter; Predicate_i* myPredicate; @@ -886,6 +933,8 @@ namespace SMESH Skew_ptr CreateSkew(); Area_ptr CreateArea(); Volume3D_ptr CreateVolume3D(); + MaxElementLength2D_ptr CreateMaxElementLength2D(); + MaxElementLength3D_ptr CreateMaxElementLength3D(); Length_ptr CreateLength(); Length2D_ptr CreateLength2D(); MultiConnection_ptr CreateMultiConnection(); @@ -904,13 +953,11 @@ namespace SMESH FreeFaces_ptr CreateFreeFaces(); RangeOfIds_ptr CreateRangeOfIds(); - BadOrientedVolume_ptr CreateBadOrientedVolume(); LinearOrQuadratic_ptr CreateLinearOrQuadratic(); - GroupColor_ptr CreateGroupColor(); - ElemGeomType_ptr CreateElemGeomType(); + CoplanarFaces_ptr CreateCoplanarFaces(); LessThan_ptr CreateLessThan(); MoreThan_ptr CreateMoreThan(); diff --git a/src/SMESH_I/SMESH_Gen_i.cxx b/src/SMESH_I/SMESH_Gen_i.cxx index 49ec45fad..a0ce885aa 100644 --- a/src/SMESH_I/SMESH_Gen_i.cxx +++ b/src/SMESH_I/SMESH_Gen_i.cxx @@ -889,7 +889,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMeshesFromUNV( const char* theFileName aStudyBuilder->CommitCommand(); if ( !aSO->_is_nil() ) { // Update Python script - TPythonDump() << aSO << " = smeshgen.CreateMeshesFromUNV('" << theFileName << "')"; + TPythonDump() << aSO << " = smeshgen.CreateMeshesFromUNV(r'" << theFileName << "')"; } } @@ -932,7 +932,6 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName, // Python Dump TPythonDump aPythonDump; aPythonDump << "(["; - //TCollection_AsciiString aStr ("(["); if (theStatus == SMESH::DRS_OK) { SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder(); @@ -943,7 +942,6 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName, // Iterate through all meshes and create mesh objects for ( list::iterator it = aNames.begin(); it != aNames.end(); it++ ) { // Python Dump - //if (i > 0) aStr += ", "; if (i > 0) aPythonDump << ", "; // create mesh @@ -956,12 +954,9 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName, if ( !aSO->_is_nil() ) { // Python Dump aPythonDump << aSO; - //aStr += aSO->GetID(); } else { // Python Dump aPythonDump << "mesh_" << i; -// aStr += "mesh_"; -// aStr += TCollection_AsciiString(i); } // Read mesh data (groups are published automatically by ImportMEDFile()) @@ -978,7 +973,7 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName, } // Update Python script - aPythonDump << "], status) = " << this << ".CreateMeshesFromMED('" << theFileName << "')"; + aPythonDump << "], status) = " << this << ".CreateMeshesFromMED(r'" << theFileName << "')"; } // Dump creation of groups for ( int i = 0; i < aResult->length(); ++i ) @@ -1012,7 +1007,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMeshesFromSTL( const char* theFileName aStudyBuilder->CommitCommand(); if ( !aSO->_is_nil() ) { // Update Python script - TPythonDump() << aSO << " = " << this << ".CreateMeshesFromSTL('" << theFileName << "')"; + TPythonDump() << aSO << " = " << this << ".CreateMeshesFromSTL(r'" << theFileName << "')"; } } @@ -1431,7 +1426,9 @@ CORBA::Boolean SMESH_Gen_i::Compute( SMESH::SMESH_Mesh_ptr theMesh, myLocShape = SMESH_Mesh::PseudoShape(); // call implementation compute ::SMESH_Mesh& myLocMesh = meshServant->GetImpl(); - return myGen.Compute( myLocMesh, myLocShape); + bool ok = myGen.Compute( myLocMesh, myLocShape); + meshServant->CreateGroupServants(); // algos can create groups (issue 0020918) + return ok; } } catch ( std::bad_alloc ) { @@ -2157,7 +2154,7 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray, if (theMergeNodesAndElements) { // merge nodes - set aMeshNodes; // no input nodes + TIDSortedNodeSet aMeshNodes; // no input nodes SMESH_MeshEditor::TListOfListOfNodes aGroupsOfNodes; aNewEditor.FindCoincidentNodes( aMeshNodes, theMergeTolerance, aGroupsOfNodes ); aNewEditor.MergeNodes( aGroupsOfNodes ); @@ -2323,6 +2320,38 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, DriverMED_W_SMESHDS_Mesh myWriter; myWriter.SetFile( meshfile.ToCString() ); + // IMP issue 20918 + // 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 ); + for ( ; itBig->More(); itBig->Next() ) { + SALOMEDS::SObject_var gotBranch = itBig->Value(); + if ( gotBranch->Tag() > GetAlgorithmsRootTag() ) { + CORBA::Object_var anObject = SObjectToObject( gotBranch ); + if ( !CORBA::is_nil( anObject ) ) { + SMESH::SMESH_Mesh_var myMesh = SMESH::SMESH_Mesh::_narrow( anObject ) ; + if ( !myMesh->_is_nil() ) { + SMESH::ListOfGroups_var groups = myMesh->GetGroups(); + for ( int i = 0; i < groups->length(); ++i ) + { + SMESH_GroupBase_i* grImpl = SMESH::DownCast( groups[i]); + if ( grImpl ) + { + CORBA::String_var objStr = GetORB()->object_to_string( grImpl->_this() ); + int anId = myStudyContext->findId( string( objStr.in() ) ); + char grpName[ 30 ]; + sprintf( grpName, "Group %d", anId ); + SMESHDS_GroupBase* aGrpBaseDS = grImpl->GetGroupDS(); + aGrpBaseDS->SetStoreName( grpName ); + } + } + } + } + } + } + } + // Write data // ---> create HDF file aFile = new HDFfile( (char*) filename.ToCString() ); @@ -2519,13 +2548,21 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aDataset->CloseOnDisk(); // issue 0020693. Store _isModified flag - int isModified = myImpl->GetImpl().GetIsModified(); + int isModified = myLocMesh.GetIsModified(); aSize[ 0 ] = 1; aDataset = new HDFdataset( "_isModified", aTopGroup, HDF_INT32, aSize, 1 ); aDataset->CreateOnDisk(); aDataset->WriteOnDisk( &isModified ); aDataset->CloseOnDisk(); + // issue 20918. Store Persistent Id of SMESHDS_Mesh + int meshPersistentId = mySMESHDSMesh->GetPersistentId(); + aSize[ 0 ] = 1; + aDataset = new HDFdataset( "meshPersistentId", aTopGroup, HDF_INT32, aSize, 1 ); + aDataset->CreateOnDisk(); + aDataset->WriteOnDisk( &meshPersistentId ); + aDataset->CloseOnDisk(); + // write reference on a shape if exists SALOMEDS::SObject_var myRef; bool shapeRefFound = false; @@ -2869,17 +2906,19 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, dynamic_cast( GetServant( aSubObject ).in() ); if ( !myGroupImpl ) continue; + SMESHDS_GroupBase* aGrpBaseDS = myGroupImpl->GetGroupDS(); + if ( !aGrpBaseDS ) + continue; CORBA::String_var objStr = GetORB()->object_to_string( aSubObject ); int anId = myStudyContext->findId( string( objStr.in() ) ); - + // For each group, create a dataset named "Group " // and store the group's user name into it - char grpName[ 30 ]; - sprintf( grpName, "Group %d", anId ); + const char* grpName = aGrpBaseDS->GetStoreName(); char* aUserName = myGroupImpl->GetName(); aSize[ 0 ] = strlen( aUserName ) + 1; - + aDataset = new HDFdataset( grpName, aGroup, HDF_STRING, aSize, 1 ); aDataset->CreateOnDisk(); aDataset->WriteOnDisk( aUserName ); @@ -2901,46 +2940,36 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aDataset->WriteOnDisk( anRGB ); aDataset->CloseOnDisk(); - // Store the group contents into MED file - if ( myLocMesh.GetGroup( myGroupImpl->GetLocalID() ) ) { - - if(MYDEBUG) MESSAGE( "VSR - SMESH_Gen_i::Save(): saving group with StoreName = " - << grpName << " to MED file" ); - SMESHDS_GroupBase* aGrpBaseDS = - myLocMesh.GetGroup( myGroupImpl->GetLocalID() )->GetGroupDS(); - aGrpBaseDS->SetStoreName( grpName ); - - // Pass SMESHDS_Group to MED writer - SMESHDS_Group* aGrpDS = dynamic_cast( aGrpBaseDS ); - if ( aGrpDS ) - myWriter.AddGroup( aGrpDS ); - - // write reference on a shape if exists - SMESHDS_GroupOnGeom* aGeomGrp = - dynamic_cast( aGrpBaseDS ); - if ( aGeomGrp ) { - SALOMEDS::SObject_var mySubRef, myShape; - if (mySObject->FindSubObject( GetRefOnShapeTag(), mySubRef ) && - mySubRef->ReferencedObject( myShape ) && - !CORBA::is_nil( myShape->GetObject() )) - { - string myRefOnObject = myShape->GetID(); - if ( myRefOnObject.length() > 0 ) { - char aRefName[ 30 ]; - sprintf( aRefName, "Ref on shape %d", anId); - aSize[ 0 ] = myRefOnObject.length() + 1; - aDataset = new HDFdataset(aRefName, aGroup, HDF_STRING, aSize, 1); - aDataset->CreateOnDisk(); - aDataset->WriteOnDisk( ( char* )( myRefOnObject.c_str() ) ); - aDataset->CloseOnDisk(); - } - } - else // shape ref is invalid: - { - // save a group on geometry as ordinary group - myWriter.AddGroup( aGeomGrp ); + // Pass SMESHDS_Group to MED writer + SMESHDS_Group* aGrpDS = dynamic_cast( aGrpBaseDS ); + if ( aGrpDS ) + myWriter.AddGroup( aGrpDS ); + + // write reference on a shape if exists + SMESHDS_GroupOnGeom* aGeomGrp = + dynamic_cast( aGrpBaseDS ); + if ( aGeomGrp ) { + SALOMEDS::SObject_var mySubRef, myShape; + if (mySObject->FindSubObject( GetRefOnShapeTag(), mySubRef ) && + mySubRef->ReferencedObject( myShape ) && + !CORBA::is_nil( myShape->GetObject() )) + { + string myRefOnObject = myShape->GetID(); + if ( myRefOnObject.length() > 0 ) { + char aRefName[ 30 ]; + sprintf( aRefName, "Ref on shape %d", anId); + aSize[ 0 ] = myRefOnObject.length() + 1; + aDataset = new HDFdataset(aRefName, aGroup, HDF_STRING, aSize, 1); + aDataset->CreateOnDisk(); + aDataset->WriteOnDisk( ( char* )( myRefOnObject.c_str() ) ); + aDataset->CloseOnDisk(); } } + else // shape ref is invalid: + { + // save a group on geometry as ordinary group + myWriter.AddGroup( aGeomGrp ); + } } } } @@ -3247,13 +3276,15 @@ public: } PositionCreator() { myFuncTable.resize( (size_t) TopAbs_SHAPE, & PositionCreator::defaultPosition ); - myFuncTable[ TopAbs_FACE ] = & PositionCreator::facePosition; - myFuncTable[ TopAbs_EDGE ] = & PositionCreator::edgePosition; + myFuncTable[ TopAbs_SOLID ] = & PositionCreator::volumePosition; + myFuncTable[ TopAbs_FACE ] = & PositionCreator::facePosition; + myFuncTable[ TopAbs_EDGE ] = & PositionCreator::edgePosition; myFuncTable[ TopAbs_VERTEX ] = & PositionCreator::vertexPosition; } private: SMDS_PositionPtr edgePosition() const { return SMDS_PositionPtr( new SMDS_EdgePosition ); } SMDS_PositionPtr facePosition() const { return SMDS_PositionPtr( new SMDS_FacePosition ); } + SMDS_PositionPtr volumePosition() const { return SMDS_PositionPtr( new SMDS_SpacePosition ); } SMDS_PositionPtr vertexPosition() const { return SMDS_PositionPtr( new SMDS_VertexPosition); } SMDS_PositionPtr defaultPosition() const { return SMDS_SpacePosition::originSpacePosition(); } typedef SMDS_PositionPtr (PositionCreator:: * FmakePos)() const; @@ -3628,6 +3659,18 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aDataset->CloseOnDisk(); myNewMeshImpl->GetImpl().SetIsModified( bool(*isModified)); } + + // issue 20918. Restore Persistent Id of SMESHDS_Mesh + if( aTopGroup->ExistInternalObject( "meshPersistentId" ) ) + { + aDataset = new HDFdataset( "meshPersistentId", aTopGroup ); + aDataset->OpenOnDisk(); + size = aDataset->GetSize(); + int* meshPersistentId = new int[ size ]; + aDataset->ReadFromDisk( meshPersistentId ); + aDataset->CloseOnDisk(); + myNewMeshImpl->GetImpl().GetMeshDS()->SetPersistentId( *meshPersistentId ); + } } } } @@ -3942,7 +3985,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aGroup = new HDFgroup( "Submeshes", aTopGroup ); aGroup->OpenOnDisk(); - int maxID = mySMESHDSMesh->MaxShapeIndex(); + int maxID = Max( mySMESHDSMesh->MaxSubMeshIndex(), mySMESHDSMesh->MaxShapeIndex() ); vector< SMESHDS_SubMesh * > subMeshes( maxID + 1, (SMESHDS_SubMesh*) 0 ); vector< TopAbs_ShapeEnum > smType ( maxID + 1, TopAbs_SHAPE ); @@ -4130,20 +4173,6 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, } // if ( aTopGroup->ExistInternalObject( "Node Positions" ) ) } // if ( hasData ) - // Recompute State (as computed sub-meshes are restored from MED) - if ( !aShapeObject->_is_nil() || !myNewMeshImpl->HasShapeToMesh()) { - MESSAGE("Compute State Engine ..."); - TopoDS_Shape myLocShape; - if(myNewMeshImpl->HasShapeToMesh()) - myLocShape = GeomObjectToShape( aShapeObject ); - else - myLocShape = SMESH_Mesh::PseudoShape(); - - myNewMeshImpl->GetImpl().GetSubMesh(myLocShape)->ComputeStateEngine - (SMESH_subMesh::SUBMESH_RESTORED); - MESSAGE("Compute State Engine finished"); - } - // try to get groups for ( int ii = GetNodeGroupsTag(); ii <= GetVolumeGroupsTag(); ii++ ) { char name_group[ 30 ]; @@ -4250,6 +4279,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aGroup->CloseOnDisk(); } } + // read submeh order if any if( aTopGroup->ExistInternalObject( "Mesh Order" ) ) { aDataset = new HDFdataset( "Mesh Order", aTopGroup ); @@ -4268,7 +4298,30 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, myNewMeshImpl->GetImpl().SetMeshOrder( anOrderIds ); } + } // loop on meshes + + // notify algos on completed restoration + for ( meshi_group = meshGroupList.begin(); meshi_group != meshGroupList.end(); ++meshi_group ) + { + SMESH_Mesh_i* myNewMeshImpl = meshi_group->first; + ::SMESH_Mesh& myLocMesh = myNewMeshImpl->GetImpl(); + + TopoDS_Shape myLocShape; + if(myLocMesh.HasShapeToMesh()) + myLocShape = myLocMesh.GetShapeToMesh(); + else + myLocShape = SMESH_Mesh::PseudoShape(); + + myLocMesh.GetSubMesh(myLocShape)-> + ComputeStateEngine (SMESH_subMesh::SUBMESH_RESTORED); } + + for ( hyp_data = hypDataList.begin(); hyp_data != hypDataList.end(); ++hyp_data ) + { + SMESH_Hypothesis_i* hyp = hyp_data->first; + hyp->UpdateAsMeshesRestored(); // for hyps needing full mesh data restored (issue 20918) + } + // close mesh group if(aTopGroup) aTopGroup->CloseOnDisk(); diff --git a/src/SMESH_I/SMESH_Gen_i.hxx b/src/SMESH_I/SMESH_Gen_i.hxx index 89cf79ca7..b2c90805c 100644 --- a/src/SMESH_I/SMESH_Gen_i.hxx +++ b/src/SMESH_I/SMESH_Gen_i.hxx @@ -223,7 +223,7 @@ public: SMESH::SMESH_Mesh_ptr CreateEmptyMesh() throw ( SALOME::SALOME_Exception ); - // Create mesh(es) and import data from UNV file + // Create mesh(es) and import data from UNV fileter SMESH::SMESH_Mesh_ptr CreateMeshesFromUNV( const char* theFileName ) throw ( SALOME::SALOME_Exception ); @@ -357,6 +357,9 @@ public: // Return a pattern mesher SMESH::SMESH_Pattern_ptr GetPattern(); + // Create measurement instance + SMESH::Measurements_ptr CreateMeasurements(); + // Clears study-connected data when it is closed void Close( SALOMEDS::SComponent_ptr theComponent ); diff --git a/src/SMESH_I/SMESH_Gen_i_1.cxx b/src/SMESH_I/SMESH_Gen_i_1.cxx index d5161e29f..5a82382d6 100644 --- a/src/SMESH_I/SMESH_Gen_i_1.cxx +++ b/src/SMESH_I/SMESH_Gen_i_1.cxx @@ -19,14 +19,14 @@ // // 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_Gen_i_1.cxx -// Created : Thu Oct 21 17:24:06 2004 -// Author : Edward AGAPOV (eap) -// Module : SMESH -// $Header: // +// File : SMESH_Gen_i_1.cxx +// Created : Thu Oct 21 17:24:06 2004 +// Author : Edward AGAPOV (eap) +// Module : SMESH +// $Header : $ + #include "SMESH_Gen_i.hxx" #include "SMESH_Mesh_i.hxx" @@ -923,7 +923,30 @@ void SMESH_Gen_i::UpdateParameters(CORBA::Object_ptr theObject, const char* theP if(!hasAttr) aNewParams = anInputParams; else - aNewParams = aOldParameters+"|"+anInputParams; + { + int pos = aOldParameters.SearchFromEnd("|"); + if(pos==-1) pos = 0; + TCollection_AsciiString previousParamFull(aOldParameters.Split(pos)); + TCollection_AsciiString previousParam(previousParamFull); + TCollection_AsciiString theRepet("1"); + pos = previousParam.SearchFromEnd(";*="); + if(pos >= 0) + { + theRepet = previousParam.Split(pos+2); + pos = pos-1; + if(pos==-1) pos = 0; + previousParam.Split(pos); + } + if(previousParam == anInputParams) + { + theRepet = theRepet.IntegerValue()+1; + aNewParams = aOldParameters + previousParam + ";*=" + theRepet; + } + else + { + aNewParams = aOldParameters + previousParamFull + "|" + anInputParams; + } + } if(VARIABLE_DEBUG) { diff --git a/src/SMESH_I/SMESH_Group_i.cxx b/src/SMESH_I/SMESH_Group_i.cxx index c69024ed2..592d172ba 100644 --- a/src/SMESH_I/SMESH_Group_i.cxx +++ b/src/SMESH_I/SMESH_Group_i.cxx @@ -36,6 +36,8 @@ #include "SMESH_Filter_i.hxx" #include "SMESH_PythonDump.hxx" +#include CORBA_SERVER_HEADER(SMESH_Filter) + #include "utilities.h" using namespace SMESH; @@ -347,6 +349,37 @@ RemoveByPredicate( SMESH::Predicate_ptr thePredicate ) return 0; } +CORBA::Long SMESH_Group_i::AddFrom( SMESH::SMESH_IDSource_ptr theSource ) +{ + long nbAdd = 0; + SMESHDS_Group* aGroupDS = dynamic_cast( GetGroupDS() ); + if (aGroupDS) { + SMESH::long_array_var anIds; + SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theSource); + SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow(theSource); + SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow(theSource); + SMESH::Filter_var filter = SMESH::Filter::_narrow(theSource); + if ( !group->_is_nil()) + anIds = group->GetType()==GetType() ? theSource->GetIDs() : new SMESH::long_array(); + else if ( !mesh->_is_nil() ) + anIds = mesh->GetElementsByType( GetType() ); + else if ( !submesh->_is_nil()) + anIds = submesh->GetElementsByType( GetType() ); + else if ( !filter->_is_nil() ) + anIds = filter->GetElementType()==GetType() ? theSource->GetIDs() : new SMESH::long_array(); + else + anIds = theSource->GetIDs(); + for ( int i = 0, total = anIds->length(); i < total; i++ ) { + if ( aGroupDS->Add((int)anIds[i]) ) nbAdd++; + } + } + + // Update Python script + TPythonDump() << "nbAdd = " << _this() << ".AddFrom( " << theSource << " )"; + + return nbAdd; +} + //============================================================================= /*! * @@ -396,17 +429,6 @@ SMESH::SMESH_Mesh_ptr SMESH_GroupBase_i::GetMesh() return aMesh._retn(); } -//============================================================================= -/*! - * - */ -//============================================================================= -SMESH::long_array* SMESH_GroupBase_i::GetIDs() -{ - SMESH::long_array_var aResult = GetListOfID(); - return aResult._retn(); -} - //======================================================================= //function : GetShape //purpose : @@ -513,3 +535,28 @@ SMESH::long_array* SMESH_GroupBase_i::GetMeshInfo() SMESH_Mesh_i::CollectMeshInfo( aGrpDS->GetElements(), aRes); return aRes._retn(); } + +//======================================================================= +//function : GetIDs +//purpose : Returns ids of members +//======================================================================= + +SMESH::long_array* SMESH_GroupBase_i::GetIDs() +{ + SMESH::long_array_var aResult = GetListOfID(); + return aResult._retn(); +} + +//======================================================================= +//function : GetTypes +//purpose : Returns types of elements it contains +//======================================================================= + +SMESH::array_of_ElementType* SMESH_GroupBase_i::GetTypes() +{ + SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType; + types->length( 1 ); + types[0] = GetType(); + return types._retn(); +} + diff --git a/src/SMESH_I/SMESH_Group_i.hxx b/src/SMESH_I/SMESH_Group_i.hxx index 30ea828c0..3b1b08eaa 100644 --- a/src/SMESH_I/SMESH_Group_i.hxx +++ b/src/SMESH_I/SMESH_Group_i.hxx @@ -75,6 +75,12 @@ class SMESH_I_EXPORT SMESH_GroupBase_i: // Inherited from SMESH_IDSource interface virtual SMESH::long_array* GetIDs(); + /*! + * Returns types of elements it contains + * Inherited from SMESH_IDSource interface + */ + virtual SMESH::array_of_ElementType* GetTypes(); + // Internal C++ interface int GetLocalID() const { return myLocalID; } SMESH_Mesh_i* GetMeshServant() const { return myMeshServant; } @@ -92,7 +98,7 @@ private: int myLocalID; void changeLocalId(int localId) { myLocalID = localId; } - friend void SMESH_Mesh_i::CheckGeomGroupModif(); + friend class SMESH_Mesh_i; }; // ====== @@ -113,6 +119,8 @@ class SMESH_I_EXPORT SMESH_Group_i: CORBA::Long AddByPredicate( SMESH::Predicate_ptr thePredicate ); CORBA::Long RemoveByPredicate( SMESH::Predicate_ptr thePredicate ); + + CORBA::Long AddFrom( SMESH::SMESH_IDSource_ptr theSource ); }; // ========================= diff --git a/src/SMESH_I/SMESH_Hypothesis_i.cxx b/src/SMESH_I/SMESH_Hypothesis_i.cxx index 19d436ff6..8875e4d1f 100644 --- a/src/SMESH_I/SMESH_Hypothesis_i.cxx +++ b/src/SMESH_I/SMESH_Hypothesis_i.cxx @@ -279,4 +279,17 @@ void SMESH_Hypothesis_i::LoadFrom( const char* theStream ) MESSAGE( "SMESH_Hypothesis_i::LoadFrom" ); std::istringstream is( theStream ); myBaseImpl->LoadFrom( is ); + // let listeners know about loading (issue 0020918) + myBaseImpl->NotifySubMeshesHypothesisModification(); +} + +//================================================================================ +/*! + * \brief This mesthod is called after completion of loading a study + */ +//================================================================================ + +void SMESH_Hypothesis_i::UpdateAsMeshesRestored() +{ + // for hyps needing full data restored } diff --git a/src/SMESH_I/SMESH_Hypothesis_i.hxx b/src/SMESH_I/SMESH_Hypothesis_i.hxx index 24c01d46a..99eba89ca 100644 --- a/src/SMESH_I/SMESH_Hypothesis_i.hxx +++ b/src/SMESH_I/SMESH_Hypothesis_i.hxx @@ -91,7 +91,8 @@ public: // Persistence virtual char* SaveTo(); virtual void LoadFrom( const char* theStream ); - + virtual void UpdateAsMeshesRestored(); // for hyps needing full data restored + protected: ::SMESH_Hypothesis* myBaseImpl; // base hypothesis implementation }; diff --git a/src/SMESH_I/SMESH_MEDFamily_i.cxx b/src/SMESH_I/SMESH_MEDFamily_i.cxx index 66d26cc0d..8dbd37d19 100644 --- a/src/SMESH_I/SMESH_MEDFamily_i.cxx +++ b/src/SMESH_I/SMESH_MEDFamily_i.cxx @@ -126,7 +126,7 @@ throw (SALOME::SALOME_Exception) * CORBA: Accessor for attributes identifiers */ //============================================================================= -SALOME_MED::long_array* SMESH_MEDFamily_i::getAttributesIdentifiers() +SALOME_TYPES::ListOfLong* SMESH_MEDFamily_i::getAttributesIdentifiers() throw (SALOME::SALOME_Exception) { if (_subMeshDS==NULL) @@ -139,7 +139,7 @@ throw (SALOME::SALOME_Exception) ,SALOME::BAD_PARAM); }; - SALOME_MED::long_array_var myseq= new SALOME_MED::long_array; + SALOME_TYPES::ListOfLong_var myseq= new SALOME_TYPES::ListOfLong; myseq->length(_numberOfAttribute); for (int i=0;i<_numberOfAttribute;i++) { @@ -176,7 +176,7 @@ CORBA::Long SMESH_MEDFamily_i::getAttributeIdentifier(CORBA::Long i) * CORBA: Accessor for attributes values */ //============================================================================= -SALOME_MED::long_array* SMESH_MEDFamily_i::getAttributesValues() +SALOME_TYPES::ListOfLong* SMESH_MEDFamily_i::getAttributesValues() throw (SALOME::SALOME_Exception) { if (_subMeshDS==NULL) @@ -190,7 +190,7 @@ SALOME_MED::long_array* SMESH_MEDFamily_i::getAttributesValues() ,SALOME::BAD_PARAM); }; - SALOME_MED::long_array_var myseq= new SALOME_MED::long_array; + SALOME_TYPES::ListOfLong_var myseq= new SALOME_TYPES::ListOfLong; myseq->length(_numberOfAttribute); for (int i=0;i<_numberOfAttribute;i++) { @@ -224,7 +224,7 @@ CORBA::Long SMESH_MEDFamily_i::getAttributeValue(CORBA::Long i) * CORBA: Accessor for attributes desriptions */ //============================================================================= -SALOME_MED::string_array * SMESH_MEDFamily_i::getAttributesDescriptions() +SALOME_TYPES::ListOfString * SMESH_MEDFamily_i::getAttributesDescriptions() throw (SALOME::SALOME_Exception) { if (_subMeshDS==NULL) @@ -236,7 +236,7 @@ SALOME_MED::string_array * SMESH_MEDFamily_i::getAttributesDescriptions() THROW_SALOME_CORBA_EXCEPTION("No attributes"\ ,SALOME::BAD_PARAM); } - SALOME_MED::string_array_var myseq = new SALOME_MED::string_array; + SALOME_TYPES::ListOfString_var myseq = new SALOME_TYPES::ListOfString; for (int i=0;i<_numberOfAttribute;i++) { myseq[i]=CORBA::string_dup(_attributeDescription[i].c_str()); @@ -292,7 +292,7 @@ char * SMESH_MEDFamily_i::getGroupName( CORBA::Long i) * CORBA: Accessor for all the groups name */ //============================================================================= -SALOME_MED::string_array* SMESH_MEDFamily_i::getGroupsNames() +SALOME_TYPES::ListOfString* SMESH_MEDFamily_i::getGroupsNames() throw (SALOME::SALOME_Exception) { MESSAGE("!!! NOT YET IMPLEMENTED !!!!"); diff --git a/src/SMESH_I/SMESH_MEDFamily_i.hxx b/src/SMESH_I/SMESH_MEDFamily_i.hxx index 06a13600d..27f4d80b5 100644 --- a/src/SMESH_I/SMESH_MEDFamily_i.hxx +++ b/src/SMESH_I/SMESH_MEDFamily_i.hxx @@ -70,15 +70,15 @@ public : throw (SALOME::SALOME_Exception); CORBA::Long getNumberOfAttributes() throw (SALOME::SALOME_Exception); - SALOME_MED::long_array* getAttributesIdentifiers() + SALOME_TYPES::ListOfLong* getAttributesIdentifiers() throw (SALOME::SALOME_Exception); CORBA::Long getAttributeIdentifier(CORBA::Long i) throw (SALOME::SALOME_Exception); - SALOME_MED::long_array* getAttributesValues() + SALOME_TYPES::ListOfLong* getAttributesValues() throw (SALOME::SALOME_Exception); CORBA::Long getAttributeValue(CORBA::Long i) throw (SALOME::SALOME_Exception); - SALOME_MED::string_array* getAttributesDescriptions() + SALOME_TYPES::ListOfString* getAttributesDescriptions() throw (SALOME::SALOME_Exception); char* getAttributeDescription( CORBA::Long i) throw (SALOME::SALOME_Exception); @@ -86,7 +86,7 @@ public : throw (SALOME::SALOME_Exception); char * getGroupName( CORBA::Long i) throw (SALOME::SALOME_Exception); - SALOME_MED::string_array* getGroupsNames() + SALOME_TYPES::ListOfString* getGroupsNames() throw (SALOME::SALOME_Exception); }; #endif /* MED_FAMILY_I_HXX_ */ diff --git a/src/SMESH_I/SMESH_MEDMesh_i.cxx b/src/SMESH_I/SMESH_MEDMesh_i.cxx index b1b093770..e69b00e45 100644 --- a/src/SMESH_I/SMESH_MEDMesh_i.cxx +++ b/src/SMESH_I/SMESH_MEDMesh_i.cxx @@ -248,13 +248,13 @@ char *SMESH_MEDMesh_i::getCoordinatesSystem() throw(SALOME::SALOME_Exception) * CORBA: Accessor for Coordinates */ //============================================================================= -SALOME_MED::double_array * SMESH_MEDMesh_i::getCoordinates +SALOME_TYPES::ListOfDouble * SMESH_MEDMesh_i::getCoordinates (SALOME_MED::medModeSwitch typeSwitch) throw(SALOME::SALOME_Exception) { if (_mesh_i == 0) THROW_SALOME_CORBA_EXCEPTION("No associated Mesh", SALOME::INTERNAL_ERROR); - SALOME_MED::double_array_var myseq = new SALOME_MED::double_array; + SALOME_TYPES::ListOfDouble_var myseq = new SALOME_TYPES::ListOfDouble; try { // PN : En dur @@ -305,13 +305,13 @@ SALOME_MED::double_array * SMESH_MEDMesh_i::getCoordinates * CORBA: Accessor for Coordinates Names */ //============================================================================= -SALOME_MED::string_array * +SALOME_TYPES::ListOfString * SMESH_MEDMesh_i::getCoordinatesNames()throw(SALOME::SALOME_Exception) { if (_mesh_i == 0) THROW_SALOME_CORBA_EXCEPTION("No associated Mesh", SALOME::INTERNAL_ERROR); - SALOME_MED::string_array_var myseq = new SALOME_MED::string_array; + SALOME_TYPES::ListOfString_var myseq = new SALOME_TYPES::ListOfString; try { // PN : en dur @@ -336,13 +336,13 @@ SMESH_MEDMesh_i::getCoordinatesNames()throw(SALOME::SALOME_Exception) * CORBA: Accessor for Coordinates Units */ //============================================================================= -SALOME_MED::string_array * +SALOME_TYPES::ListOfString * SMESH_MEDMesh_i::getCoordinatesUnits()throw(SALOME::SALOME_Exception) { if (_mesh_i == 0) THROW_SALOME_CORBA_EXCEPTION("No associated Mesh", SALOME::INTERNAL_ERROR); - SALOME_MED::string_array_var myseq = new SALOME_MED::string_array; + SALOME_TYPES::ListOfString_var myseq = new SALOME_TYPES::ListOfString; try { // PN : en dur @@ -509,7 +509,7 @@ CORBA::Long SMESH_MEDMesh_i::getNumberOfElements(SALOME_MED:: * CORBA: Accessor for connectivities */ //============================================================================= -SALOME_MED::long_array * +SALOME_TYPES::ListOfLong * SMESH_MEDMesh_i::getConnectivity(SALOME_MED::medModeSwitch typeSwitch, SALOME_MED::medConnectivity mode, SALOME_MED::medEntityMesh entity, @@ -541,7 +541,7 @@ SMESH_MEDMesh_i::getConnectivity(SALOME_MED::medModeSwitch typeSwitch, * CORBA: Accessor for connectivities */ //============================================================================= -SALOME_MED::long_array * +SALOME_TYPES::ListOfLong * SMESH_MEDMesh_i::getConnectivityIndex(SALOME_MED::medConnectivity mode, SALOME_MED::medEntityMesh entity) throw(SALOME::SALOME_Exception) @@ -560,7 +560,7 @@ CORBA::Long SMESH_MEDMesh_i::getElementNumber(SALOME_MED::medConnectivity mode, SALOME_MED::medEntityMesh entity, SALOME_MED::medGeometryElement type, - const SALOME_MED::long_array & connectivity) + const SALOME_TYPES::ListOfLong & connectivity) throw(SALOME::SALOME_Exception) { const char *LOC = "getElementNumber "; @@ -575,7 +575,7 @@ SMESH_MEDMesh_i::getElementNumber(SALOME_MED::medConnectivity mode, * not implemented for MED_ALL_ENTITIES and MED_MAILLE */ //============================================================================= -SALOME_MED::long_array * +SALOME_TYPES::ListOfLong * SMESH_MEDMesh_i::getReverseConnectivity(SALOME_MED:: medConnectivity mode) throw(SALOME::SALOME_Exception) { @@ -589,7 +589,7 @@ SMESH_MEDMesh_i::getReverseConnectivity(SALOME_MED:: * CORBA: Accessor for connectivities */ //============================================================================= -SALOME_MED::long_array * +SALOME_TYPES::ListOfLong * SMESH_MEDMesh_i::getReverseConnectivityIndex(SALOME_MED:: medConnectivity mode) throw(SALOME::SALOME_Exception) { @@ -708,7 +708,7 @@ SALOME_MED::GROUP_ptr SMESH_MEDMesh_i::getGroup(SALOME_MED:: * CORBA: Returns references for the global numbering index */ //============================================================================= -SALOME_MED::long_array* +SALOME_TYPES::ListOfLong* SMESH_MEDMesh_i::getGlobalNumberingIndex(SALOME_MED::medEntityMesh entity) throw (SALOME::SALOME_Exception) { diff --git a/src/SMESH_I/SMESH_MEDMesh_i.hxx b/src/SMESH_I/SMESH_MEDMesh_i.hxx index 68fcc96c3..fa49725f5 100644 --- a/src/SMESH_I/SMESH_MEDMesh_i.hxx +++ b/src/SMESH_I/SMESH_MEDMesh_i.hxx @@ -63,7 +63,7 @@ protected: int _famIdent; std::map < SALOME_MED::medGeometryElement, int >_mapIndToSeqElts; - SALOME_MED::long_array_var _seq_elemId[MED_NBR_GEOMETRIE_MAILLE]; + SALOME_TYPES::ListOfLong_var _seq_elemId[MED_NBR_GEOMETRIE_MAILLE]; std::map < SALOME_MED::medEntityMesh, int >_mapNbTypes; std::map < SALOME_MED::medEntityMesh, int >_mapIndToVectTypes; @@ -112,13 +112,13 @@ public: CORBA::Double getCoordinate(CORBA::Long Number, CORBA::Long Axis) throw (SALOME::SALOME_Exception); - SALOME_MED::double_array * getCoordinates(SALOME_MED::medModeSwitch typeSwitch) + SALOME_TYPES::ListOfDouble * getCoordinates(SALOME_MED::medModeSwitch typeSwitch) throw(SALOME::SALOME_Exception); - SALOME_MED::string_array * getCoordinatesNames() + SALOME_TYPES::ListOfString * getCoordinatesNames() throw(SALOME::SALOME_Exception); - SALOME_MED::string_array * getCoordinatesUnits() + SALOME_TYPES::ListOfString * getCoordinatesUnits() throw(SALOME::SALOME_Exception); CORBA::Long getNumberOfNodes() throw(SALOME::SALOME_Exception); @@ -139,33 +139,33 @@ public: SALOME_MED::medGeometryElement geomElement) throw(SALOME::SALOME_Exception); - SALOME_MED::long_array * + SALOME_TYPES::ListOfLong * getConnectivity(SALOME_MED::medModeSwitch typeSwitch, SALOME_MED::medConnectivity mode, SALOME_MED::medEntityMesh entity, SALOME_MED::medGeometryElement geomElement) throw(SALOME::SALOME_Exception); - SALOME_MED::long_array * + SALOME_TYPES::ListOfLong * getConnectivityIndex(SALOME_MED::medConnectivity mode, SALOME_MED::medEntityMesh entity) throw(SALOME::SALOME_Exception); - SALOME_MED::long_array* + SALOME_TYPES::ListOfLong* getGlobalNumberingIndex(SALOME_MED::medEntityMesh entity) throw (SALOME::SALOME_Exception); CORBA::Long getElementNumber(SALOME_MED::medConnectivity mode, SALOME_MED::medEntityMesh entity, SALOME_MED::medGeometryElement type, - const SALOME_MED::long_array & connectivity) + const SALOME_TYPES::ListOfLong & connectivity) throw(SALOME::SALOME_Exception); - SALOME_MED::long_array * + SALOME_TYPES::ListOfLong * getReverseConnectivity(SALOME_MED::medConnectivity mode) throw(SALOME::SALOME_Exception); - SALOME_MED::long_array * + SALOME_TYPES::ListOfLong * getReverseConnectivityIndex(SALOME_MED::medConnectivity mode) throw(SALOME::SALOME_Exception); diff --git a/src/SMESH_I/SMESH_MEDSupport_i.cxx b/src/SMESH_I/SMESH_MEDSupport_i.cxx index c1a8fe548..adc941cbf 100644 --- a/src/SMESH_I/SMESH_MEDSupport_i.cxx +++ b/src/SMESH_I/SMESH_MEDSupport_i.cxx @@ -296,7 +296,7 @@ CORBA::Long SMESH_MEDSupport_i::getNumberOfElements(SALOME_MED:: */ //============================================================================= -SALOME_MED::long_array * SMESH_MEDSupport_i::getNumber( +SALOME_TYPES::ListOfLong * SMESH_MEDSupport_i::getNumber( SALOME_MED::medGeometryElement geomElement) throw(SALOME::SALOME_Exception) { Unexpect aCatch(SALOME_SalomeException); @@ -308,7 +308,7 @@ SALOME_MED::long_array * SMESH_MEDSupport_i::getNumber( if (geomElement != SALOME_MED::MED_NONE) THROW_SALOME_CORBA_EXCEPTION("Not implemented", SALOME::BAD_PARAM); - SALOME_MED::long_array_var myseq = new SALOME_MED::long_array; + SALOME_TYPES::ListOfLong_var myseq = new SALOME_TYPES::ListOfLong; int i = 0; myseq->length(_subMeshDS->NbNodes()); @@ -332,7 +332,7 @@ SALOME_MED::long_array * SMESH_MEDSupport_i::getNumber( */ //============================================================================= -SALOME_MED::long_array * SMESH_MEDSupport_i::getNumberFromFile( +SALOME_TYPES::ListOfLong * SMESH_MEDSupport_i::getNumberFromFile( SALOME_MED::medGeometryElement geomElement) throw(SALOME::SALOME_Exception) { return getNumber(geomElement); @@ -345,7 +345,7 @@ SALOME_MED::long_array * SMESH_MEDSupport_i::getNumberFromFile( */ //============================================================================= -SALOME_MED::long_array * +SALOME_TYPES::ListOfLong * SMESH_MEDSupport_i::getNumberIndex()throw(SALOME::SALOME_Exception) { MESSAGE("Not implemented for SMESH_i"); @@ -382,7 +382,7 @@ CORBA::Long SMESH_MEDSupport_i::getNumberOfTypes() * included in the support */ //============================================================================= -SALOME_MED::long_array* SMESH_MEDSupport_i::getNumbersOfGaussPoint() +SALOME_TYPES::ListOfLong* SMESH_MEDSupport_i::getNumbersOfGaussPoint() throw (SALOME::SALOME_Exception) { MESSAGE("!!! NOT YET IMPLEMENTED !!!!"); diff --git a/src/SMESH_I/SMESH_MEDSupport_i.hxx b/src/SMESH_I/SMESH_MEDSupport_i.hxx index b30528dad..5e8c821af 100644 --- a/src/SMESH_I/SMESH_MEDSupport_i.hxx +++ b/src/SMESH_I/SMESH_MEDSupport_i.hxx @@ -64,25 +64,25 @@ class SMESH_I_EXPORT SMESH_MEDSupport_i: CORBA::Long getNumberOfTypes() throw (SALOME::SALOME_Exception); - SALOME_MED::long_array * + SALOME_TYPES::ListOfLong * getNumber(SALOME_MED::medGeometryElement geomElement) throw(SALOME::SALOME_Exception); /*! * Same function as getNumber. */ - SALOME_MED::long_array * + SALOME_TYPES::ListOfLong * getNumberFromFile(SALOME_MED::medGeometryElement geomElement) throw(SALOME::SALOME_Exception); - SALOME_MED::long_array * getNumberIndex() + SALOME_TYPES::ListOfLong * getNumberIndex() throw(SALOME::SALOME_Exception); CORBA::Long getNumberOfGaussPoint(SALOME_MED::medGeometryElement geomElement) throw(SALOME::SALOME_Exception); - SALOME_MED::long_array* getNumbersOfGaussPoint() + SALOME_TYPES::ListOfLong* getNumbersOfGaussPoint() throw (SALOME::SALOME_Exception); SALOME_MED::medGeometryElement_array *getTypes() diff --git a/src/SMESH_I/SMESH_Measurements_i.cxx b/src/SMESH_I/SMESH_Measurements_i.cxx new file mode 100644 index 000000000..1397a4c39 --- /dev/null +++ b/src/SMESH_I/SMESH_Measurements_i.cxx @@ -0,0 +1,259 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SMESH_Measurements_i.cxx +// Author : Pavel TELKOV, Open CASCADE S.A.S. (pavel.telkov@opencascade.com) + +#include "SMESH_Measurements_i.hxx" + +#include "SMESH_Gen_i.hxx" +#include "SMESH_PythonDump.hxx" + +#include "SMDS_Mesh.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_MeshElement.hxx" +#include "SMDS_ElemIterator.hxx" + +#include "SMESHDS_Mesh.hxx" + + +using namespace SMESH; + +/** + * this local function to avoid uninitialized fields + */ +static void initMeasure( SMESH::Measure& theMeasure) +{ + + theMeasure.minX = theMeasure.minY = theMeasure.minZ = 0.; + theMeasure.maxX = theMeasure.maxY = theMeasure.maxZ = 0.; + theMeasure.node1 = theMeasure.node2 = -1; + theMeasure.elem1 = theMeasure.elem2 = -1; + theMeasure.value = 0.; +} + +//============================================================================= +/*! + * SMESH_Gen_i::CreateMeasurements + * + * Create measurement instance + */ +//============================================================================= + +SMESH::Measurements_ptr SMESH_Gen_i::CreateMeasurements() +{ + SMESH::Measurements_i* aMeasure = new SMESH::Measurements_i(); + SMESH::Measurements_var anObj = aMeasure->_this(); + return anObj._retn(); +} + + +/* + Class : Measurements + Description : make measure of mesh qunatities +*/ + +//======================================================================= +// name : Measurements_i +// Purpose : Constructor +//======================================================================= +Measurements_i::Measurements_i() +: SALOME::GenericObj_i( SMESH_Gen_i::GetPOA() ) +{ + //Base class Salome_GenericObject do it inmplicitly by overriding PortableServer::POA_ptr _default_POA() method + //PortableServer::ObjectId_var anObjectId = + // SMESH_Gen_i::GetPOA()->activate_object( this ); +} + +//======================================================================= +// name : ~Measurements_i +// Purpose : Destructor +//======================================================================= +Measurements_i::~Measurements_i() +{ + //TPythonDump()<X(); if (theNode2) dd -= theNode2->X(); theMeasure.minX = dd; dd *= dd; dist += dd; + dd = theNode1->Y(); if (theNode2) dd -= theNode2->Y(); theMeasure.minY = dd; dd *= dd; dist += dd; + dd = theNode1->Z(); if (theNode2) dd -= theNode2->Z(); theMeasure.minZ = dd; dd *= dd; dist += dd; + + if (dist < 0) + return false; + + theMeasure.value = sqrt(dist); + theMeasure.node1 = theNode1->GetID(); + theMeasure.node2 = theNode2 ? theNode2->GetID() : 0; + + return true; +} + +static SMESHDS_Mesh* getMesh(SMESH::SMESH_IDSource_ptr theSource) +{ + if (!CORBA::is_nil( theSource )) + { + SMESH_Mesh_i* anImplPtr = DownCast(theSource->GetMesh()); + if (anImplPtr) + return anImplPtr->GetImpl().GetMeshDS(); + } + return 0; +} + +static bool isNodeType (SMESH::array_of_ElementType_var theTypes) +{ + return theTypes->length() > 0 && theTypes[0] == SMESH::NODE; +} + +//======================================================================= +// name : MinDistance +// Purpose : minimal distance between two given entities +//======================================================================= +SMESH::Measure Measurements_i::MinDistance + (SMESH::SMESH_IDSource_ptr theSource1, + SMESH::SMESH_IDSource_ptr theSource2) +{ + SMESH::Measure aMeasure; + initMeasure(aMeasure); + + if (CORBA::is_nil( theSource1 )) + return aMeasure; + + // if second source is null, min distance from theSource1 to the origin is calculated + bool isOrigin = CORBA::is_nil( theSource2 ); + + // calculate minimal distance between two mesh entities + SMESH::array_of_ElementType_var types1 = theSource1->GetTypes(); + SMESH::array_of_ElementType_var types2; + if ( !isOrigin ) types2 = theSource2->GetTypes(); + + // here we assume that type of all IDs defined by first type in array + bool isNode1 = isNodeType(types1); + bool isNode2 = isOrigin || isNodeType(types2); + + SMESH::long_array_var aElementsId1 = theSource1->GetIDs(); + SMESH::long_array_var aElementsId2; + if ( !isOrigin ) aElementsId2 = theSource2->GetIDs(); + + // compute distance between two entities + /* NOTE: currently only node-to-node case is implemented + * all other cases will be implemented later + * below IF should be replaced by complete switch + * on mesh entities types + */ + if (isNode1 && isNode2) + { + // node - node + const SMESHDS_Mesh* aMesh1 = getMesh( theSource1 ); + const SMESHDS_Mesh* aMesh2 = isOrigin ? 0 : getMesh( theSource2 ); + const SMDS_MeshNode* theNode1 = aMesh1 ? aMesh1->FindNode( aElementsId1[0] ) : 0; + const SMDS_MeshNode* theNode2 = aMesh2 ? aMesh2->FindNode( aElementsId2[0] ) : 0; + getNodeNodeDistance( aMeasure, theNode1, theNode2 ); + } + else + { + // NOT_IMPLEMENTED + } + + return aMeasure; +} + +//======================================================================= +// name : enlargeBoundingBox +// Purpose : +//======================================================================= +static void enlargeBoundingBox(const SMDS_MeshNode* theNode, + SMESH::Measure& theMeasure) +{ + if (!theNode) + return; + if ( theMeasure.node1 == -1 ) { + // we use this attribute as a flag that it is the first node added to the bnd box + theMeasure.minX = theMeasure.maxX = theNode->X(); + theMeasure.minY = theMeasure.maxY = theNode->Y(); + theMeasure.minZ = theMeasure.maxZ = theNode->Z(); + theMeasure.node1 = theNode->GetID(); + } + else { + theMeasure.minX = min( theMeasure.minX, theNode->X() ); + theMeasure.maxX = max( theMeasure.maxX, theNode->X() ); + theMeasure.minY = min( theMeasure.minY, theNode->Y() ); + theMeasure.maxY = max( theMeasure.maxY, theNode->Y() ); + theMeasure.minZ = min( theMeasure.minZ, theNode->Z() ); + theMeasure.maxZ = max( theMeasure.maxZ, theNode->Z() ); + } +} + +//======================================================================= +// name : enlargeBoundingBox +// Purpose : +//======================================================================= +static void enlargeBoundingBox(const SMESH::SMESH_IDSource_ptr theObject, + SMESH::Measure& theMeasure) +{ + if ( CORBA::is_nil( theObject ) ) + return; + const SMESHDS_Mesh* aMesh = getMesh( theObject ); + if ( !aMesh ) + return; + SMESH::array_of_ElementType_var types = theObject->GetTypes(); + SMESH::long_array_var aElementsId = theObject->GetIDs(); + // here we assume that type of all IDs defined by first type in array + const bool isNode = isNodeType( types ); + for(int i = 0, n = aElementsId->length(); i < n; i++) + { + if (isNode) + enlargeBoundingBox( aMesh->FindNode( aElementsId[i] ), theMeasure); + else + { + const SMDS_MeshElement* elem = aMesh->FindElement( aElementsId[i] ); + if (!elem) + continue; + SMDS_ElemIteratorPtr aNodeIter = elem->nodesIterator(); + while( aNodeIter->more() ) + enlargeBoundingBox( dynamic_cast( aNodeIter->next() ), theMeasure); + } + } +} + +//======================================================================= +// name : BoundingBox +// Purpose : compute common bounding box of entities +//======================================================================= +SMESH::Measure Measurements_i::BoundingBox (const SMESH::ListOfIDSources& theSources) +{ + SMESH::Measure aMeasure; + initMeasure(aMeasure); + + // calculate bounding box on sources + for ( int i = 0, n = theSources.length(); i < n ; ++i ) + enlargeBoundingBox( theSources[i], aMeasure ); + + return aMeasure; +} diff --git a/src/SMESH_I/SMESH_Measurements_i.hxx b/src/SMESH_I/SMESH_Measurements_i.hxx new file mode 100644 index 000000000..0e1d77dcf --- /dev/null +++ b/src/SMESH_I/SMESH_Measurements_i.hxx @@ -0,0 +1,63 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SMESH_Measurements_i.hxx +// Author : Pavel TELKOV, Open CASCADE S.A.S. (pavel.telkov@opencascade.com) + +#ifndef _SMESH_MEASUREMENTS_I_HXX_ +#define _SMESH_MEASUREMENTS_I_HXX_ + +#include "SMESH.hxx" + +#include +#include CORBA_SERVER_HEADER(SMESH_Measurements) + +#include "SALOME_GenericObj_i.hh" + +class SMESHDS_Mesh; + +namespace SMESH +{ + + /* + Measurements + */ + class SMESH_I_EXPORT Measurements_i: public virtual POA_SMESH::Measurements, + public virtual SALOME::GenericObj_i + { + public: + Measurements_i(); + ~Measurements_i(); + + /*! + * minimal distance between two given entities + */ + SMESH::Measure MinDistance(SMESH::SMESH_IDSource_ptr theSource1, + SMESH::SMESH_IDSource_ptr theSource2); + + /*! + * common bounding box of entities + */ + SMESH::Measure BoundingBox(const SMESH::ListOfIDSources& theSources); + }; +} + +#endif diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index 6887ed0a1..d442601d5 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -25,6 +25,10 @@ // Author : Nicolas REJNERI // Module : SMESH // +#ifdef WNT +#define NOMINMAX +#endif + #include "SMESH_MeshEditor_i.hxx" #include "SMDS_Mesh0DElement.hxx" @@ -32,13 +36,13 @@ #include "SMDS_MeshFace.hxx" #include "SMDS_MeshVolume.hxx" #include "SMDS_PolyhedralVolumeOfNodes.hxx" -#include "SMESH_MeshEditor.hxx" #include "SMESH_subMeshEventListener.hxx" #include "SMESH_Gen_i.hxx" #include "SMESH_Filter_i.hxx" #include "SMESH_subMesh_i.hxx" #include "SMESH_Group_i.hxx" #include "SMESH_PythonDump.hxx" +#include "SMESH_ControlsDef.hxx" #include "utilities.h" #include "Utils_ExceptHandlers.hxx" @@ -65,6 +69,7 @@ #endif #include +#include #define cast2Node(elem) static_cast( elem ) @@ -228,6 +233,91 @@ namespace { } return typeStr; } + //================================================================================ + /*! + * \brief function for conversion long_array to TIDSortedElemSet + * \param IDs - array of IDs + * \param aMesh - mesh + * \param aMap - collection to fill + * \param aType - element type + */ + //================================================================================ + + void arrayToSet(const SMESH::long_array & IDs, + const SMESHDS_Mesh* aMesh, + TIDSortedElemSet& aMap, + const SMDSAbs_ElementType aType = SMDSAbs_All ) + { + for (int i=0; iFindNode(ind) : aMesh->FindElement(ind)); + if ( elem && ( aType == SMDSAbs_All || elem->GetType() == aType )) + aMap.insert( elem ); + } + } + //================================================================================ + /*! + * \brief Retrieve elements of given type from SMESH_IDSource + */ + //================================================================================ + + bool idSourceToSet(SMESH::SMESH_IDSource_ptr theIDSource, + const SMESHDS_Mesh* theMeshDS, + TIDSortedElemSet& theElemSet, + const SMDSAbs_ElementType theType, + const bool emptyIfIsMesh=false) + + { + if ( CORBA::is_nil( theIDSource ) ) + return false; + if ( emptyIfIsMesh && SMESH::DownCast( theIDSource )) + return true; + + SMESH::long_array_var anIDs = theIDSource->GetIDs(); + if ( anIDs->length() == 0 ) + return false; + SMESH::array_of_ElementType_var types = theIDSource->GetTypes(); + if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes + { + if ( theType == SMDSAbs_All || theType == SMDSAbs_Node ) + arrayToSet( anIDs, theMeshDS, theElemSet, SMDSAbs_Node ); + else + return false; + } + else + { + arrayToSet( anIDs, theMeshDS, theElemSet, theType); + } + return true; + } + //================================================================================ + /*! + * \brief Retrieve nodes from SMESH_IDSource + */ + //================================================================================ + + void idSourceToNodeSet(SMESH::SMESH_IDSource_ptr theObject, + const SMESHDS_Mesh* theMeshDS, + TIDSortedNodeSet& theNodeSet) + + { + if ( CORBA::is_nil( theObject ) ) + return; + SMESH::array_of_ElementType_var types = theObject->GetTypes(); + SMESH::long_array_var aElementsId = theObject->GetIDs(); + if ( types->length() == 1 && types[0] == SMESH::NODE) + { + for(int i = 0; i < aElementsId->length(); i++) + if ( const SMDS_MeshNode * n = theMeshDS->FindNode( aElementsId[i] )) + theNodeSet.insert( theNodeSet.end(), n); + } + else { + for(int i = 0; i < aElementsId->length(); i++) + if( const SMDS_MeshElement * elem = theMeshDS->FindElement( aElementsId[i] )) + theNodeSet.insert( elem->begin_nodes(), elem->end_nodes()); + } + } } //============================================================================= @@ -279,17 +369,30 @@ void SMESH_MeshEditor_i::initData(bool deleteSearchers) struct _IDSource : public POA_SMESH::SMESH_IDSource { - SMESH::long_array _ids; + SMESH::long_array _ids; + SMESH::ElementType _type; + SMESH::SMESH_Mesh_ptr _mesh; SMESH::long_array* GetIDs() { return new SMESH::long_array( _ids ); } SMESH::long_array* GetMeshInfo() { return 0; } + SMESH::SMESH_Mesh_ptr GetMesh() { return SMESH::SMESH_Mesh::_duplicate( _mesh ); } + SMESH::array_of_ElementType* GetTypes() + { + SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType; + types->length( 1 ); + types[0] = _type; + return types._retn(); + } }; -SMESH::SMESH_IDSource_ptr SMESH_MeshEditor_i::MakeIDSource(const SMESH::long_array& ids) +SMESH::SMESH_IDSource_ptr SMESH_MeshEditor_i::MakeIDSource(const SMESH::long_array& ids, + SMESH::ElementType type) { _IDSource* anIDSource = new _IDSource; anIDSource->_ids = ids; + anIDSource->_type = type; + anIDSource->_mesh = myMesh_i->_this(); SMESH::SMESH_IDSource_var anIDSourceVar = anIDSource->_this(); - + return anIDSourceVar._retn(); } @@ -350,6 +453,37 @@ CORBA::Boolean SMESH_MeshEditor_i::RemoveNodes(const SMESH::long_array & IDsOfNo */ //============================================================================= +CORBA::Long SMESH_MeshEditor_i::RemoveOrphanNodes() +{ + initData(); + + ::SMESH_MeshEditor anEditor( myMesh ); + + // Update Python script + TPythonDump() << "nbRemoved = " << this << ".RemoveOrphanNodes()"; + + // Create filter to find all orphan nodes + SMESH::Controls::Filter::TIdSequence seq; + SMESH::Controls::PredicatePtr predicate( new SMESH::Controls::FreeNodes() ); + SMESH::Controls::Filter::GetElementsId( GetMeshDS(), predicate, seq ); + + // remove orphan nodes (if there are any) + list< int > IdList; + for ( int i = 0; i < seq.size(); i++ ) + IdList.push_back( seq[i] ); + + if ( IdList.size() ) + myMesh->SetIsModified( true ); + + return anEditor.Remove( IdList, true ); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + CORBA::Long SMESH_MeshEditor_i::AddNode(CORBA::Double x, CORBA::Double y, CORBA::Double z) { @@ -900,34 +1034,6 @@ CORBA::Boolean SMESH_MeshEditor_i::ReorientObject(SMESH::SMESH_IDSource_ptr theO return isDone; } -namespace -{ - //================================================================================ - /*! - * \brief function for conversion long_array to TIDSortedElemSet - * \param IDs - array of IDs - * \param aMesh - mesh - * \param aMap - collection to fill - * \param aType - element type - */ - //================================================================================ - - void arrayToSet(const SMESH::long_array & IDs, - const SMESHDS_Mesh* aMesh, - TIDSortedElemSet& aMap, - const SMDSAbs_ElementType aType = SMDSAbs_All ) - { - for (int i=0; iFindNode(ind) - : aMesh->FindElement(ind)); - if ( elem && ( aType == SMDSAbs_All || elem->GetType() == aType )) - aMap.insert( elem ); - } - } -} - //============================================================================= /*! * @@ -1116,6 +1222,8 @@ CORBA::Boolean SMESH_MeshEditor_i::SplitQuadObject (SMESH::SMESH_IDSource_ptr th CORBA::Long SMESH_MeshEditor_i::BestSplit (CORBA::Long IDOfQuad, SMESH::NumericalFunctor_ptr Criterion) { + initData(); + const SMDS_MeshElement* quad = GetMeshDS()->FindElement(IDOfQuad); if (quad && quad->GetType() == SMDSAbs_Face && quad->NbNodes() == 4) { @@ -1145,6 +1253,8 @@ void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems, { Unexpect aCatch(SALOME_SalomeException); + initData(); + SMESH::long_array_var anElementsId = elems->GetIDs(); TIDSortedElemSet elemSet; arrayToSet( anElementsId, GetMeshDS(), elemSet, SMDSAbs_Volume ); @@ -2726,7 +2836,7 @@ SMESH_MeshEditor_i::LinearAnglesVariation(SMESH::SMESH_Mesh_ptr thePathMes //======================================================================= SMESH::ListOfGroups* -SMESH_MeshEditor_i::mirror(const SMESH::long_array & theIDsOfElements, +SMESH_MeshEditor_i::mirror(TIDSortedElemSet & theElements, const SMESH::AxisStruct & theAxis, SMESH::SMESH_MeshEditor::MirrorType theMirrorType, CORBA::Boolean theCopy, @@ -2735,9 +2845,6 @@ SMESH_MeshEditor_i::mirror(const SMESH::long_array & theIDsOfElements, { initData(); - TIDSortedElemSet elements; - arrayToSet(theIDsOfElements, GetMeshDS(), elements); - gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z ); gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz ); @@ -2755,7 +2862,7 @@ SMESH_MeshEditor_i::mirror(const SMESH::long_array & theIDsOfElements, ::SMESH_MeshEditor anEditor( myMesh ); ::SMESH_MeshEditor::PGroupIDs groupIds = - anEditor.Transform (elements, aTrsf, theCopy, theMakeGroups, theTargetMesh); + anEditor.Transform (theElements, aTrsf, theCopy, theMakeGroups, theTargetMesh); if(theCopy) storeResult(anEditor); @@ -2782,7 +2889,12 @@ void SMESH_MeshEditor_i::Mirror(const SMESH::long_array & theIDsOfElem << mirrorTypeName(theMirrorType) << ", " << theCopy << " )"; } - mirror(theIDsOfElements, theAxis, theMirrorType, theCopy, false); + if ( theIDsOfElements.length() > 0 ) + { + TIDSortedElemSet elements; + arrayToSet(theIDsOfElements, GetMeshDS(), elements); + mirror(elements, theAxis, theMirrorType, theCopy, false); + } } @@ -2803,8 +2915,9 @@ void SMESH_MeshEditor_i::MirrorObject(SMESH::SMESH_IDSource_ptr theObj << mirrorTypeName(theMirrorType) << ", " << theCopy << " )"; } - SMESH::long_array_var anElementsId = theObject->GetIDs(); - mirror(anElementsId, theAxis, theMirrorType, theCopy, false); + TIDSortedElemSet elements; + if (idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) + mirror(elements, theAxis, theMirrorType, theCopy, false); } //======================================================================= @@ -2817,7 +2930,13 @@ SMESH_MeshEditor_i::MirrorMakeGroups(const SMESH::long_array& theIDsO const SMESH::AxisStruct& theMirror, SMESH::SMESH_MeshEditor::MirrorType theMirrorType) { - SMESH::ListOfGroups * aGroups = mirror(theIDsOfElements, theMirror, theMirrorType, true, true); + SMESH::ListOfGroups * aGroups = 0; + if ( theIDsOfElements.length() > 0 ) + { + TIDSortedElemSet elements; + arrayToSet(theIDsOfElements, GetMeshDS(), elements); + aGroups = mirror(elements, theMirror, theMirrorType, true, true); + } if ( !myPreviewMode ) { TPythonDump aPythonDump; DumpGroupsList(aPythonDump,aGroups); @@ -2839,9 +2958,13 @@ SMESH_MeshEditor_i::MirrorObjectMakeGroups(SMESH::SMESH_IDSource_ptr t const SMESH::AxisStruct& theMirror, SMESH::SMESH_MeshEditor::MirrorType theMirrorType) { - SMESH::long_array_var anElementsId = theObject->GetIDs(); - SMESH::ListOfGroups * aGroups = mirror(anElementsId, theMirror, theMirrorType, true, true); - if ( !myPreviewMode ) { + SMESH::ListOfGroups * aGroups = 0; + TIDSortedElemSet elements; + if ( idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) + aGroups = mirror(elements, theMirror, theMirrorType, true, true); + + if ( !myPreviewMode ) + { TPythonDump aPythonDump; DumpGroupsList(aPythonDump,aGroups); aPythonDump << this << ".MirrorObjectMakeGroups( " @@ -2873,8 +2996,11 @@ SMESH_MeshEditor_i::MirrorMakeMesh(const SMESH::long_array& theIDsOfE mesh = makeMesh( theMeshName ); mesh_i = SMESH::DownCast( mesh ); - if (mesh_i) { - mirror(theIDsOfElements, theMirror, theMirrorType, + if (mesh_i && theIDsOfElements.length() > 0 ) + { + TIDSortedElemSet elements; + arrayToSet(theIDsOfElements, GetMeshDS(), elements); + mirror(elements, theMirror, theMirrorType, false, theCopyGroups, & mesh_i->GetImpl()); mesh_i->CreateGroupServants(); } @@ -2917,13 +3043,14 @@ SMESH_MeshEditor_i::MirrorObjectMakeMesh(SMESH::SMESH_IDSource_ptr the mesh = makeMesh( theMeshName ); mesh_i = SMESH::DownCast( mesh ); - if ( mesh_i ) { - SMESH::long_array_var anElementsId = theObject->GetIDs(); - mirror(anElementsId, theMirror, theMirrorType, + TIDSortedElemSet elements; + if ( mesh_i && + idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) + { + mirror(elements, theMirror, theMirrorType, false, theCopyGroups, & mesh_i->GetImpl()); mesh_i->CreateGroupServants(); } - if ( !myPreviewMode ) { pydump << mesh << " = " << this << ".MirrorObjectMakeMesh( " << theObject << ", " @@ -2932,7 +3059,7 @@ SMESH_MeshEditor_i::MirrorObjectMakeMesh(SMESH::SMESH_IDSource_ptr the << theCopyGroups << ", '" << theMeshName << "' )"; } - } + } //dump "GetGroups" if(!myPreviewMode && mesh_i) @@ -2947,7 +3074,7 @@ SMESH_MeshEditor_i::MirrorObjectMakeMesh(SMESH::SMESH_IDSource_ptr the //======================================================================= SMESH::ListOfGroups* -SMESH_MeshEditor_i::translate(const SMESH::long_array & theIDsOfElements, +SMESH_MeshEditor_i::translate(TIDSortedElemSet & theElements, const SMESH::DirStruct & theVector, CORBA::Boolean theCopy, const bool theMakeGroups, @@ -2955,16 +3082,13 @@ SMESH_MeshEditor_i::translate(const SMESH::long_array & theIDsOfElements, { initData(); - TIDSortedElemSet elements; - arrayToSet(theIDsOfElements, GetMeshDS(), elements); - gp_Trsf aTrsf; const SMESH::PointStruct * P = &theVector.PS; aTrsf.SetTranslation( gp_Vec( P->x, P->y, P->z )); ::SMESH_MeshEditor anEditor( myMesh ); ::SMESH_MeshEditor::PGroupIDs groupIds = - anEditor.Transform (elements, aTrsf, theCopy, theMakeGroups, theTargetMesh); + anEditor.Transform (theElements, aTrsf, theCopy, theMakeGroups, theTargetMesh); if(theCopy) storeResult(anEditor); @@ -2989,10 +3113,12 @@ void SMESH_MeshEditor_i::Translate(const SMESH::long_array & theIDsOfElements, << theVector << ", " << theCopy << " )"; } - translate(theIDsOfElements, - theVector, - theCopy, - false); + if ( theIDsOfElements.length() ) + { + TIDSortedElemSet elements; + arrayToSet(theIDsOfElements, GetMeshDS(), elements); + translate(elements,theVector,theCopy,false); + } } //======================================================================= @@ -3010,11 +3136,9 @@ void SMESH_MeshEditor_i::TranslateObject(SMESH::SMESH_IDSource_ptr theObject, << theVector << ", " << theCopy << " )"; } - SMESH::long_array_var anElementsId = theObject->GetIDs(); - translate(anElementsId, - theVector, - theCopy, - false); + TIDSortedElemSet elements; + if ( idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) + translate( elements, theVector, theCopy, false); } //======================================================================= @@ -3026,7 +3150,13 @@ SMESH::ListOfGroups* SMESH_MeshEditor_i::TranslateMakeGroups(const SMESH::long_array& theIDsOfElements, const SMESH::DirStruct& theVector) { - SMESH::ListOfGroups * aGroups = translate(theIDsOfElements,theVector,true,true); + SMESH::ListOfGroups * aGroups = 0; + if ( theIDsOfElements.length() ) + { + TIDSortedElemSet elements; + arrayToSet(theIDsOfElements, GetMeshDS(), elements); + aGroups = translate(elements,theVector,true,true); + } if ( !myPreviewMode ) { TPythonDump aPythonDump; DumpGroupsList(aPythonDump,aGroups); @@ -3046,8 +3176,10 @@ SMESH::ListOfGroups* SMESH_MeshEditor_i::TranslateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject, const SMESH::DirStruct& theVector) { - SMESH::long_array_var anElementsId = theObject->GetIDs(); - SMESH::ListOfGroups * aGroups = translate(anElementsId, theVector, true, true); + SMESH::ListOfGroups * aGroups = 0; + TIDSortedElemSet elements; + if (idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) + aGroups = translate(elements, theVector, true, true); if ( !myPreviewMode ) { @@ -3082,9 +3214,11 @@ SMESH_MeshEditor_i::TranslateMakeMesh(const SMESH::long_array& theIDsOfElements, mesh = makeMesh( theMeshName ); mesh_i = SMESH::DownCast( mesh ); - if ( mesh_i ) { - translate(theIDsOfElements, theVector, - false, theCopyGroups, & mesh_i->GetImpl()); + if ( mesh_i && theIDsOfElements.length() ) + { + TIDSortedElemSet elements; + arrayToSet(theIDsOfElements, GetMeshDS(), elements); + translate(elements, theVector, false, theCopyGroups, & mesh_i->GetImpl()); mesh_i->CreateGroupServants(); } @@ -3124,10 +3258,11 @@ SMESH_MeshEditor_i::TranslateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject, mesh = makeMesh( theMeshName ); mesh_i = SMESH::DownCast( mesh ); - if ( mesh_i ) { - SMESH::long_array_var anElementsId = theObject->GetIDs(); - translate(anElementsId, theVector, - false, theCopyGroups, & mesh_i->GetImpl()); + TIDSortedElemSet elements; + if ( mesh_i && + idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) + { + translate(elements, theVector,false, theCopyGroups, & mesh_i->GetImpl()); mesh_i->CreateGroupServants(); } if ( !myPreviewMode ) { @@ -3152,7 +3287,7 @@ SMESH_MeshEditor_i::TranslateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject, //======================================================================= SMESH::ListOfGroups* -SMESH_MeshEditor_i::rotate(const SMESH::long_array & theIDsOfElements, +SMESH_MeshEditor_i::rotate(TIDSortedElemSet & theElements, const SMESH::AxisStruct & theAxis, CORBA::Double theAngle, CORBA::Boolean theCopy, @@ -3161,9 +3296,6 @@ SMESH_MeshEditor_i::rotate(const SMESH::long_array & theIDsOfElements, { initData(); - TIDSortedElemSet elements; - arrayToSet(theIDsOfElements, GetMeshDS(), elements); - gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z ); gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz ); @@ -3172,7 +3304,7 @@ SMESH_MeshEditor_i::rotate(const SMESH::long_array & theIDsOfElements, ::SMESH_MeshEditor anEditor( myMesh ); ::SMESH_MeshEditor::PGroupIDs groupIds = - anEditor.Transform (elements, aTrsf, theCopy, theMakeGroups, theTargetMesh); + anEditor.Transform (theElements, aTrsf, theCopy, theMakeGroups, theTargetMesh); if(theCopy) storeResult(anEditor); @@ -3199,11 +3331,12 @@ void SMESH_MeshEditor_i::Rotate(const SMESH::long_array & theIDsOfElements, << theAngle << ", " << theCopy << " )"; } - rotate(theIDsOfElements, - theAxis, - theAngle, - theCopy, - false); + if ( theIDsOfElements.length() > 0 ) + { + TIDSortedElemSet elements; + arrayToSet(theIDsOfElements, GetMeshDS(), elements); + rotate(elements,theAxis,theAngle,theCopy,false); + } } //======================================================================= @@ -3223,12 +3356,9 @@ void SMESH_MeshEditor_i::RotateObject(SMESH::SMESH_IDSource_ptr theObject, << theAngle << ", " << theCopy << " )"; } - SMESH::long_array_var anElementsId = theObject->GetIDs(); - rotate(anElementsId, - theAxis, - theAngle, - theCopy, - false); + TIDSortedElemSet elements; + if (idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) + rotate(elements,theAxis,theAngle,theCopy,false); } //======================================================================= @@ -3241,7 +3371,13 @@ SMESH_MeshEditor_i::RotateMakeGroups(const SMESH::long_array& theIDsOfElements, const SMESH::AxisStruct& theAxis, CORBA::Double theAngle) { - SMESH::ListOfGroups * aGroups = rotate(theIDsOfElements,theAxis,theAngle,true,true); + SMESH::ListOfGroups * aGroups = 0; + if ( theIDsOfElements.length() > 0 ) + { + TIDSortedElemSet elements; + arrayToSet(theIDsOfElements, GetMeshDS(), elements); + aGroups = rotate(elements,theAxis,theAngle,true,true); + } if ( !myPreviewMode ) { TPythonDump aPythonDump; DumpGroupsList(aPythonDump,aGroups); @@ -3263,8 +3399,10 @@ SMESH_MeshEditor_i::RotateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject, const SMESH::AxisStruct& theAxis, CORBA::Double theAngle) { - SMESH::long_array_var anElementsId = theObject->GetIDs(); - SMESH::ListOfGroups * aGroups = rotate(anElementsId,theAxis,theAngle,true,true); + SMESH::ListOfGroups * aGroups = 0; + TIDSortedElemSet elements; + if ( idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) + aGroups = rotate(elements,theAxis,theAngle,true,true); if ( !myPreviewMode ) { TPythonDump aPythonDump; @@ -3300,8 +3438,11 @@ SMESH_MeshEditor_i::RotateMakeMesh(const SMESH::long_array& theIDsOfElements, mesh = makeMesh( theMeshName ); mesh_i = SMESH::DownCast( mesh ); - if ( mesh_i ) { - rotate(theIDsOfElements, theAxis, theAngleInRadians, + if ( mesh_i && theIDsOfElements.length() > 0 ) + { + TIDSortedElemSet elements; + arrayToSet(theIDsOfElements, GetMeshDS(), elements); + rotate(elements, theAxis, theAngleInRadians, false, theCopyGroups, & mesh_i->GetImpl()); mesh_i->CreateGroupServants(); } @@ -3316,7 +3457,7 @@ SMESH_MeshEditor_i::RotateMakeMesh(const SMESH::long_array& theIDsOfElements, } //dump "GetGroups" - if(!myPreviewMode && mesh_i) + if(!myPreviewMode && mesh_i && theIDsOfElements.length() > 0 ) mesh_i->GetGroups(); return mesh._retn(); @@ -3327,7 +3468,7 @@ SMESH_MeshEditor_i::RotateMakeMesh(const SMESH::long_array& theIDsOfElements, //purpose : //======================================================================= -SMESH::SMESH_Mesh_ptr +SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::RotateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject, const SMESH::AxisStruct& theAxis, CORBA::Double theAngleInRadians, @@ -3344,9 +3485,11 @@ SMESH_MeshEditor_i::RotateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject, mesh = makeMesh( theMeshName ); mesh_i = SMESH::DownCast( mesh ); - if (mesh_i ) { - SMESH::long_array_var anElementsId = theObject->GetIDs(); - rotate(anElementsId, theAxis, theAngleInRadians, + TIDSortedElemSet elements; + if (mesh_i && + idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) + { + rotate(elements, theAxis, theAngleInRadians, false, theCopyGroups, & mesh_i->GetImpl()); mesh_i->CreateGroupServants(); } @@ -3367,14 +3510,13 @@ SMESH_MeshEditor_i::RotateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject, return mesh._retn(); } - //======================================================================= //function : scale //purpose : //======================================================================= SMESH::ListOfGroups* -SMESH_MeshEditor_i::scale(const SMESH::long_array & theIDsOfElements, +SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr theObject, const SMESH::PointStruct& thePoint, const SMESH::double_array& theScaleFact, CORBA::Boolean theCopy, @@ -3382,20 +3524,28 @@ SMESH_MeshEditor_i::scale(const SMESH::long_array & theIDsOfElements, ::SMESH_Mesh* theTargetMesh) { initData(); + if ( theScaleFact.length() < 1 ) + THROW_SALOME_CORBA_EXCEPTION("Scale factor not given", SALOME::BAD_PARAM); + if ( theScaleFact.length() == 2 ) + THROW_SALOME_CORBA_EXCEPTION("Invalid nb of scale factors : 2", SALOME::BAD_PARAM); TIDSortedElemSet elements; - arrayToSet(theIDsOfElements, GetMeshDS(), elements); + if ( !idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/true)) + return 0; - gp_Pnt aPnt( thePoint.x, thePoint.y, thePoint.z ); - list aScaleFact; - for (int i = 0; i < theScaleFact.length(); i++) { - aScaleFact.push_back( theScaleFact[i] ); - } + vector S(3); + S[0] = theScaleFact[0]; + S[1] = (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[1]; + S[2] = (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[2]; + double tol = std::numeric_limits::max(); + gp_Trsf aTrsf; + aTrsf.SetValues( S[0], 0, 0, thePoint.x * (1-S[0]), + 0, S[1], 0, thePoint.y * (1-S[1]), + 0, 0, S[2], thePoint.z * (1-S[2]), tol, tol); ::SMESH_MeshEditor anEditor( myMesh ); ::SMESH_MeshEditor::PGroupIDs groupIds = - anEditor.Scale (elements, aPnt, aScaleFact, theCopy, - theMakeGroups, theTargetMesh); + anEditor.Transform (elements, aTrsf, theCopy, theMakeGroups, theTargetMesh); if(theCopy) storeResult(anEditor); @@ -3405,7 +3555,6 @@ SMESH_MeshEditor_i::scale(const SMESH::long_array & theIDsOfElements, return theMakeGroups ? getGroups(groupIds.get()) : 0; } - //======================================================================= //function : Scale //purpose : @@ -3424,8 +3573,7 @@ void SMESH_MeshEditor_i::Scale(SMESH::SMESH_IDSource_ptr theObject, << theScaleFact << ", " << theCopy << " )"; } - SMESH::long_array_var anElementsId = theObject->GetIDs(); - scale(anElementsId, thePoint, theScaleFact, theCopy, false); + scale(theObject, thePoint, theScaleFact, theCopy, false); } @@ -3439,10 +3587,7 @@ SMESH_MeshEditor_i::ScaleMakeGroups(SMESH::SMESH_IDSource_ptr theObject, const SMESH::PointStruct& thePoint, const SMESH::double_array& theScaleFact) { - SMESH::long_array_var anElementsId = theObject->GetIDs(); - SMESH::ListOfGroups * aGroups = - scale(anElementsId, thePoint, theScaleFact, true, true); - + SMESH::ListOfGroups * aGroups = scale(theObject, thePoint, theScaleFact, true, true); if ( !myPreviewMode ) { TPythonDump aPythonDump; @@ -3478,13 +3623,12 @@ SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr theObject, mesh = makeMesh( theMeshName ); mesh_i = SMESH::DownCast( mesh ); - if ( mesh_i ) { - SMESH::long_array_var anElementsId = theObject->GetIDs(); - scale(anElementsId, thePoint, theScaleFact, - false, theCopyGroups, & mesh_i->GetImpl()); + if ( mesh_i ) + { + scale(theObject, thePoint, theScaleFact,false, theCopyGroups, & mesh_i->GetImpl()); mesh_i->CreateGroupServants(); } - if ( !myPreviewMode ) { + if ( !myPreviewMode ) pydump << mesh << " = " << this << ".ScaleMakeMesh( " << theObject << ", " << "SMESH.PointStruct( " << thePoint.x << ", " @@ -3492,7 +3636,6 @@ SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr theObject, << theScaleFact << ", " << theCopyGroups << ", '" << theMeshName << "' )"; - } } //dump "GetGroups" @@ -3515,7 +3658,7 @@ void SMESH_MeshEditor_i::FindCoincidentNodes (CORBA::Double Tol ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes; ::SMESH_MeshEditor anEditor( myMesh ); - set nodes; // no input nodes + TIDSortedNodeSet nodes; // no input nodes anEditor.FindCoincidentNodes( nodes, Tolerance, aListOfListOfNodes ); GroupsOfNodes = new SMESH::array_of_long_array; @@ -3542,33 +3685,9 @@ void SMESH_MeshEditor_i::FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr SMESH::array_of_long_array_out GroupsOfNodes) { initData(); - SMESH::long_array_var aElementsId = theObject->GetIDs(); - - SMESHDS_Mesh* aMesh = GetMeshDS(); - set nodes; - - SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theObject); - if ( !group->_is_nil() && group->GetType() == SMESH::NODE) - { - for(int i = 0; i < aElementsId->length(); i++) { - CORBA::Long ind = aElementsId[i]; - const SMDS_MeshNode * elem = aMesh->FindNode(ind); - if(elem) - nodes.insert(elem); - } - } - else { - for(int i = 0; i < aElementsId->length(); i++) { - CORBA::Long ind = aElementsId[i]; - const SMDS_MeshElement * elem = aMesh->FindElement(ind); - if(elem) { - SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); - while ( nIt->more() ) - nodes.insert( nodes.end(),static_cast(nIt->next())); - } - } - } + TIDSortedNodeSet nodes; + idSourceToNodeSet( theObject, GetMeshDS(), nodes ); ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes; ::SMESH_MeshEditor anEditor( myMesh ); @@ -3578,7 +3697,8 @@ void SMESH_MeshEditor_i::FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr GroupsOfNodes = new SMESH::array_of_long_array; GroupsOfNodes->length( aListOfListOfNodes.size() ); ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin(); - for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ ) { + for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ ) + { list< const SMDS_MeshNode* >& aListOfNodes = *llIt; list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();; SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ]; @@ -3591,6 +3711,55 @@ void SMESH_MeshEditor_i::FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr << Tolerance << " )"; } +//================================================================================ +/*! + * \brief Finds nodes coinsident with Tolerance within Object excluding nodes within + * ExceptSubMeshOrGroups + */ +//================================================================================ + +void SMESH_MeshEditor_i:: +FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr theObject, + CORBA::Double theTolerance, + SMESH::array_of_long_array_out theGroupsOfNodes, + const SMESH::ListOfIDSources& theExceptSubMeshOrGroups) +{ + initData(); + + TIDSortedNodeSet nodes; + idSourceToNodeSet( theObject, GetMeshDS(), nodes ); + + for ( int i = 0; i < theExceptSubMeshOrGroups.length(); ++i ) + { + TIDSortedNodeSet exceptNodes; + idSourceToNodeSet( theExceptSubMeshOrGroups[i], GetMeshDS(), exceptNodes ); + TIDSortedNodeSet::iterator avoidNode = exceptNodes.begin(); + for ( ; avoidNode != exceptNodes.end(); ++avoidNode) + nodes.erase( *avoidNode ); + } + ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes; + ::SMESH_MeshEditor anEditor( myMesh ); + if(!nodes.empty()) + anEditor.FindCoincidentNodes( nodes, theTolerance, aListOfListOfNodes ); + + theGroupsOfNodes = new SMESH::array_of_long_array; + theGroupsOfNodes->length( aListOfListOfNodes.size() ); + ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin(); + for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ ) + { + list< const SMDS_MeshNode* >& aListOfNodes = *llIt; + list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();; + SMESH::long_array& aGroup = (*theGroupsOfNodes)[ i ]; + aGroup.length( aListOfNodes.size() ); + for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ ) + aGroup[ j ] = (*lIt)->GetID(); + } + TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPartBut( " + << theObject<<", " + << theTolerance << ", " + << theExceptSubMeshOrGroups << " )"; +} + //======================================================================= //function : MergeNodes //purpose : @@ -3750,16 +3919,39 @@ CORBA::Boolean SMESH_MeshEditor_i::MoveNode(CORBA::Long NodeID, if ( theNodeSearcher ) theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other - if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly + if ( myPreviewMode ) // make preview data + { + // in a preview mesh, make edges linked to a node + TPreviewMesh tmpMesh; + TIDSortedElemSet linkedNodes; + ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes ); + TIDSortedElemSet::iterator nIt = linkedNodes.begin(); + for ( ; nIt != linkedNodes.end(); ++nIt ) + { + SMDS_MeshEdge edge( node, cast2Node( *nIt )); + tmpMesh.Copy( &edge ); + } + // move copied node + node = tmpMesh.GetMeshDS()->FindNode( NodeID ); + if ( node ) + tmpMesh.GetMeshDS()->MoveNode(node, x, y, z); + // fill preview data + ::SMESH_MeshEditor anEditor( & tmpMesh ); + storeResult( anEditor ); + } + else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z )); else GetMeshDS()->MoveNode(node, x, y, z); - // Update Python script - TPythonDump() << "isDone = " << this << ".MoveNode( " - << NodeID << ", " << x << ", " << y << ", " << z << " )"; + if ( !myPreviewMode ) + { + // Update Python script + TPythonDump() << "isDone = " << this << ".MoveNode( " + << NodeID << ", " << x << ", " << y << ", " << z << " )"; - myMesh->SetIsModified( true ); + myMesh->SetIsModified( true ); + } return true; } @@ -4414,6 +4606,46 @@ void SMESH_MeshEditor_i::DumpGroupsList(TPythonDump & theDumpPytho } } +//================================================================================ +/*! + \brief Generates the unique group name. + \param thePrefix name prefix + \return unique name +*/ +//================================================================================ +string SMESH_MeshEditor_i::generateGroupName(const string& thePrefix) +{ + SMESH::ListOfGroups_var groups = myMesh_i->GetGroups(); + set groupNames; + + // Get existing group names + for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) { + SMESH::SMESH_GroupBase_var aGroup = groups[i]; + if (CORBA::is_nil(aGroup)) + continue; + + groupNames.insert(aGroup->GetName()); + } + + // Find new name + string name = thePrefix; + int index = 0; + + while (!groupNames.insert(name).second) { + if (index == 0) { + name += "_1"; + } + else { + TCollection_AsciiString nbStr(index+1); + name.resize( name.rfind('_')+1 ); + name += nbStr.ToCString(); + } + ++index; + } + + return name; +} + //================================================================================ /*! \brief Creates a hole in a mesh by doubling the nodes of some particular elements @@ -4447,6 +4679,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNode if ( aResult ) myMesh->SetIsModified( true ); + // Update Python script + TPythonDump() << this << ".DoubleNodes( " << theNodes << ", "<< theModifiedElems << " )"; + return aResult; } @@ -4467,9 +4702,13 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long theNodeI SMESH::long_array_var aNodes = new SMESH::long_array; aNodes->length( 1 ); aNodes[ 0 ] = theNodeId; - bool done = DoubleNodes( aNodes, theModifiedElems ); - if ( done ) - myMesh->SetIsModified( true ); + + TPythonDump pyDump; // suppress dump by the next line + + CORBA::Boolean done = DoubleNodes( aNodes, theModifiedElems ); + + pyDump << this << ".DoubleNode( " << theNodeId << ", " << theModifiedElems << " )"; + return done; } @@ -4484,9 +4723,8 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long theNodeI */ //================================================================================ -CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup( - SMESH::SMESH_GroupBase_ptr theNodes, - SMESH::SMESH_GroupBase_ptr theModifiedElems ) +CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr theNodes, + SMESH::SMESH_GroupBase_ptr theModifiedElems ) { if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE ) return false; @@ -4501,14 +4739,63 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup( aModifiedElems->length( 0 ); } + TPythonDump pyDump; // suppress dump by the next line + bool done = DoubleNodes( aNodes, aModifiedElems ); - if ( done ) - myMesh->SetIsModified( true ); + pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )"; return done; } +/*! + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements. + * Works as DoubleNodeGroup(), but returns a new group with newly created nodes. + * \param theNodes - group of nodes to be doubled. + * \param theModifiedElems - group of elements to be updated. + * \return a new group with newly created nodes + * \sa DoubleNodeGroup() + */ +SMESH::SMESH_Group_ptr SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes, + SMESH::SMESH_GroupBase_ptr theModifiedElems ) +{ + if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE ) + return false; + + SMESH::SMESH_Group_var aNewGroup; + + // Duplicate nodes + SMESH::long_array_var aNodes = theNodes->GetListOfID(); + SMESH::long_array_var aModifiedElems; + if ( !CORBA::is_nil( theModifiedElems ) ) + aModifiedElems = theModifiedElems->GetListOfID(); + else { + aModifiedElems = new SMESH::long_array; + aModifiedElems->length( 0 ); + } + + TPythonDump pyDump; // suppress dump by the next line + + bool aResult = DoubleNodes( aNodes, aModifiedElems ); + + if ( aResult ) + { + // Create group with newly created nodes + SMESH::long_array_var anIds = GetLastCreatedNodes(); + if (anIds->length() > 0) { + string anUnindexedName (theNodes->GetName()); + string aNewName = generateGroupName(anUnindexedName + "_double"); + aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str()); + aNewGroup->Add(anIds); + } + } + + pyDump << "createdNodes = " << this << ".DoubleNodeGroupNew( " << theNodes << ", " + << theModifiedElems << " )"; + + return aNewGroup._retn(); +} + //================================================================================ /*! \brief Creates a hole in a mesh by doubling the nodes of some particular elements @@ -4520,9 +4807,8 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup( */ //================================================================================ -CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups( - const SMESH::ListOfGroups& theNodes, - const SMESH::ListOfGroups& theModifiedElems ) +CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes, + const SMESH::ListOfGroups& theModifiedElems ) { initData(); @@ -4560,6 +4846,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups( if ( aResult ) myMesh->SetIsModified( true ); + + TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )"; + return aResult; } @@ -4599,8 +4888,8 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theE myMesh->SetIsModified( true ); // Update Python script - TPythonDump() << "isDone = " << this << ".DoubleNodes( " << theElems << ", " - << theNodesNot << ", " << theAffectedElems << " )"; + TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", " + << theNodesNot << ", " << theAffectedElems << " )"; return aResult; } @@ -4618,10 +4907,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theE */ //================================================================================ -CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion -( const SMESH::long_array& theElems, - const SMESH::long_array& theNodesNot, - GEOM::GEOM_Object_ptr theShape ) +CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems, + const SMESH::long_array& theNodesNot, + GEOM::GEOM_Object_ptr theShape ) { initData(); @@ -4642,8 +4930,8 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion myMesh->SetIsModified( true ); // Update Python script - TPythonDump() << "isDone = " << this << ".DoubleNodesInRegion( " << theElems << ", " - << theNodesNot << ", " << theShape << " )"; + TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", " + << theNodesNot << ", " << theShape << " )"; return aResult; } @@ -4659,18 +4947,6 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion */ //================================================================================ -static void groupToSet(SMESH::SMESH_GroupBase_ptr theGrp, - SMESHDS_Mesh* theMeshDS, - TIDSortedElemSet& theElemSet, - const SMDSAbs_ElementType theType) - -{ - if ( CORBA::is_nil( theGrp ) ) - return; - SMESH::long_array_var anIDs = theGrp->GetIDs(); - arrayToSet( anIDs, theMeshDS, theElemSet, theType); -} - CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems, SMESH::SMESH_GroupBase_ptr theNodesNot, SMESH::SMESH_GroupBase_ptr theAffectedElems) @@ -4684,9 +4960,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_pt SMESHDS_Mesh* aMeshDS = GetMeshDS(); TIDSortedElemSet anElems, aNodes, anAffected; - groupToSet( theElems, aMeshDS, anElems, SMDSAbs_All ); - groupToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node ); - groupToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All ); + idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All ); + idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node ); + idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All ); bool aResult = aMeshEditor.DoubleNodes( anElems, aNodes, anAffected ); @@ -4696,11 +4972,65 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_pt myMesh->SetIsModified( true ); // Update Python script - TPythonDump() << "isDone = " << this << ".DoubleNodeGroup( " << theElems << ", " - << theNodesNot << ", " << theAffectedElems << " )"; + TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", " + << theNodesNot << ", " << theAffectedElems << " )"; return aResult; } +/*! + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements + * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements. + * \param theElems - group of of elements (edges or faces) to be replicated + * \param theNodesNot - group of nodes not to replicated + * \param theAffectedElems - group of elements to which the replicated nodes + * should be associated to. + * \return a new group with newly created elements + * \sa DoubleNodeElemGroup() + */ +SMESH::SMESH_Group_ptr SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems, + SMESH::SMESH_GroupBase_ptr theNodesNot, + SMESH::SMESH_GroupBase_ptr theAffectedElems) +{ + if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE ) + return false; + + SMESH::SMESH_Group_var aNewGroup; + + initData(); + + ::SMESH_MeshEditor aMeshEditor( myMesh ); + + SMESHDS_Mesh* aMeshDS = GetMeshDS(); + TIDSortedElemSet anElems, aNodes, anAffected; + idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All ); + idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node ); + idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All ); + + + bool aResult = aMeshEditor.DoubleNodes( anElems, aNodes, anAffected ); + + storeResult( aMeshEditor) ; + + if ( aResult ) { + myMesh->SetIsModified( true ); + + // Create group with newly created elements + SMESH::long_array_var anIds = GetLastCreatedElems(); + if (anIds->length() > 0) { + SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true); + string anUnindexedName (theElems->GetName()); + string aNewName = generateGroupName(anUnindexedName + "_double"); + aNewGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str()); + aNewGroup->Add(anIds); + } + } + + // Update Python script + TPythonDump() << "createdElems = " << this << ".DoubleNodeElemGroupNew( " << theElems << ", " + << theNodesNot << ", " << theAffectedElems << " )"; + return aNewGroup._retn(); +} + //================================================================================ /*! \brief Creates a hole in a mesh by doubling the nodes of some particular elements @@ -4714,8 +5044,7 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_pt */ //================================================================================ -CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion( - SMESH::SMESH_GroupBase_ptr theElems, +CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems, SMESH::SMESH_GroupBase_ptr theNodesNot, GEOM::GEOM_Object_ptr theShape ) @@ -4729,8 +5058,8 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion( SMESHDS_Mesh* aMeshDS = GetMeshDS(); TIDSortedElemSet anElems, aNodes, anAffected; - groupToSet( theElems, aMeshDS, anElems, SMDSAbs_All ); - groupToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node ); + idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All ); + idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node ); TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape ); bool aResult = aMeshEditor.DoubleNodesInRegion( anElems, aNodes, aShape ); @@ -4741,8 +5070,8 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion( myMesh->SetIsModified( true ); // Update Python script - TPythonDump() << "isDone = " << this << ".DoubleNodeGroupInRegion( " << theElems << ", " - << theNodesNot << ", " << theShape << " )"; + TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", " + << theNodesNot << ", " << theShape << " )"; return aResult; } @@ -4799,7 +5128,7 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroup // Update Python script TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", " - << &theNodesNot << ", " << &theAffectedElems << " )"; + << &theNodesNot << ", " << &theAffectedElems << " )"; return aResult; } @@ -4840,8 +5169,8 @@ SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theE myMesh->SetIsModified( true ); // Update Python script - TPythonDump() << "isDone = " << this << ".DoubleNodeGroupsInRegion( " << &theElems << ", " - << &theNodesNot << ", " << theShape << " )"; + TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", " + << &theNodesNot << ", " << theShape << " )"; return aResult; } @@ -4860,7 +5189,98 @@ CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D() ::SMESH_MeshEditor aMeshEditor( myMesh ); bool aResult = aMeshEditor.Make2DMeshFrom3D(); storeResult( aMeshEditor) ; - + TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()"; return aResult; } + +// issue 20749 =================================================================== +/*! + * \brief Creates missing boundary elements + * \param elements - elements whose boundary is to be checked + * \param dimension - defines type of boundary elements to create + * \param groupName - a name of group to store created boundary elements in, + * "" means not to create the group + * \param meshName - a name of new mesh to store created boundary elements in, + * "" means not to create the new mesh + * \param toCopyElements - if true, the checked elements will be copied into the new mesh + * \param toCopyExistingBondary - if true, not only new but also pre-existing + * boundary elements will be copied into the new mesh + * \param group - returns the create group, if any + * \retval SMESH::SMESH_Mesh - the mesh where elements were added to + */ +// ================================================================================ + +SMESH::SMESH_Mesh_ptr +SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource, + SMESH::Bnd_Dimension dim, + const char* groupName, + const char* meshName, + CORBA::Boolean toCopyElements, + CORBA::Boolean toCopyExistingBondary, + SMESH::SMESH_Group_out group) +{ + initData(); + + if ( dim > SMESH::BND_1DFROM2D ) + THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM); + + + SMESHDS_Mesh* aMeshDS = GetMeshDS(); + + SMESH::SMESH_Mesh_var mesh_var; + SMESH::SMESH_Group_var group_var; + + TPythonDump pyDump; + + TIDSortedElemSet elements; + SMDSAbs_ElementType elemType = (dim == SMESH::BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume; + if ( idSourceToSet( idSource, aMeshDS, elements, elemType,/*emptyIfIsMesh=*/true )) + { + // mesh to fill in + mesh_var = + strlen(meshName) ? makeMesh(meshName) : SMESH::SMESH_Mesh::_duplicate(myMesh_i->_this()); + SMESH_Mesh_i* mesh_i = SMESH::DownCast( mesh_var ); + // other mesh + SMESH_Mesh* smesh_mesh = (mesh_i==myMesh_i) ? (SMESH_Mesh*)0 : &mesh_i->GetImpl(); + + // group of new boundary elements + SMESH_Group* smesh_group = 0; + if ( strlen(groupName) ) + { + group_var = mesh_i->CreateGroup( SMESH::ElementType(elemType),groupName); + if ( SMESH_GroupBase_i* group_i = SMESH::DownCast( group_var )) + smesh_group = group_i->GetSmeshGroup(); + } + + // do it + ::SMESH_MeshEditor aMeshEditor( myMesh ); + aMeshEditor.MakeBoundaryMesh( elements, + ::SMESH_MeshEditor::Bnd_Dimension(dim), + smesh_group, + smesh_mesh, + toCopyElements, + toCopyExistingBondary); + storeResult( aMeshEditor ); + } + + // result of MakeBoundaryMesh() is a tuple (mesh, group) + if ( mesh_var->_is_nil() ) + pyDump << myMesh_i->_this() << ", "; + else + pyDump << mesh_var << ", "; + if ( group_var->_is_nil() ) + pyDump << "_NoneGroup = "; // assignment to None is forbiden + else + pyDump << group_var << " = "; + pyDump << this << ".MakeBoundaryMesh( " + << idSource << ", " + << dim << ", " + << groupName << ", " + << meshName<< ", " + << toCopyElements << ", " + << toCopyExistingBondary << ")"; + + group = group_var._retn(); + return mesh_var._retn(); +} diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx index 046573b17..3a96b87cd 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.hxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx @@ -35,6 +35,7 @@ #include "SMESH_Mesh.hxx" #include "SMESH_PythonDump.hxx" +#include "SMESH_MeshEditor.hxx" #include class SMESH_MeshEditor; @@ -52,10 +53,11 @@ public: /*! * \brief Wrap a sequence of ids in a SMESH_IDSource */ - SMESH::SMESH_IDSource_ptr MakeIDSource(const SMESH::long_array& IDsOfElements); - + SMESH::SMESH_IDSource_ptr MakeIDSource(const SMESH::long_array& IDsOfElements, + SMESH::ElementType type); CORBA::Boolean RemoveElements(const SMESH::long_array & IDsOfElements); CORBA::Boolean RemoveNodes(const SMESH::long_array & IDsOfNodes); + CORBA::Long RemoveOrphanNodes(); /*! * Methods for creation new elements. @@ -449,6 +451,10 @@ public: void FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr Object, CORBA::Double Tolerance, SMESH::array_of_long_array_out GroupsOfNodes); + void FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr Object, + CORBA::Double Tolerance, + SMESH::array_of_long_array_out GroupsOfNodes, + const SMESH::ListOfIDSources& ExceptSubMeshOrGroups); void MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes); void FindEqualElements(SMESH::SMESH_IDSource_ptr Object, SMESH::array_of_long_array_out GroupsOfElementsID); @@ -542,7 +548,7 @@ public: */ int GetMeshId() const { return myMesh->GetId(); } - CORBA::Boolean DoubleNodes( const SMESH::long_array& theNodes, + CORBA::Boolean DoubleNodes( const SMESH::long_array& theNodes, const SMESH::long_array& theModifiedElems ); CORBA::Boolean DoubleNode( CORBA::Long theNodeId, @@ -551,6 +557,17 @@ public: CORBA::Boolean DoubleNodeGroup( SMESH::SMESH_GroupBase_ptr theNodes, SMESH::SMESH_GroupBase_ptr theModifiedElems ); + /*! + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements. + * Works as DoubleNodeGroup(), but returns a new group with newly created nodes. + * \param theNodes - group of nodes to be doubled. + * \param theModifiedElems - group of elements to be updated. + * \return a new group with newly created nodes + * \sa DoubleNodeGroup() + */ + SMESH::SMESH_Group_ptr DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes, + SMESH::SMESH_GroupBase_ptr theModifiedElems ); + CORBA::Boolean DoubleNodeGroups( const SMESH::ListOfGroups& theNodes, const SMESH::ListOfGroups& theModifiedElems); @@ -595,6 +612,20 @@ public: CORBA::Boolean DoubleNodeElemGroup( SMESH::SMESH_GroupBase_ptr theElems, SMESH::SMESH_GroupBase_ptr theNodesNot, SMESH::SMESH_GroupBase_ptr theAffectedElems ); + + /*! + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements + * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements. + * \param theElems - group of of elements (edges or faces) to be replicated + * \param theNodesNot - group of nodes not to replicated + * \param theAffectedElems - group of elements to which the replicated nodes + * should be associated to. + * \return a new group with newly created elements + * \sa DoubleNodeElemGroup() + */ + SMESH::SMESH_Group_ptr DoubleNodeElemGroupNew( SMESH::SMESH_GroupBase_ptr theElems, + SMESH::SMESH_GroupBase_ptr theNodesNot, + SMESH::SMESH_GroupBase_ptr theAffectedElems ); /*! * \brief Creates a hole in a mesh by doubling the nodes of some particular elements @@ -640,14 +671,22 @@ public: const SMESH::ListOfGroups& theNodesNot, GEOM::GEOM_Object_ptr theShape ); - /*! - * \brief Generated skin mesh (containing 2D cells) from 3D mesh - * The created 2D mesh elements based on nodes of free faces of boundary volumes - * \return TRUE if operation has been completed successfully, FALSE otherwise - */ - CORBA::Boolean Make2DMeshFrom3D(); + /*! + * \brief Generated skin mesh (containing 2D cells) from 3D mesh + * The created 2D mesh elements based on nodes of free faces of boundary volumes + * \return TRUE if operation has been completed successfully, FALSE otherwise + */ + CORBA::Boolean Make2DMeshFrom3D(); + + SMESH::SMESH_Mesh_ptr MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr elements, + SMESH::Bnd_Dimension dimension, + const char* groupName, + const char* meshName, + CORBA::Boolean toCopyElements, + CORBA::Boolean toCopyMissingBondary, + SMESH::SMESH_Group_out group); - private: //!< private methods +private: //!< private methods SMESHDS_Mesh * GetMeshDS() { return myMesh->GetMeshDS(); } @@ -706,36 +745,38 @@ public: const bool MakeGroups, const SMDSAbs_ElementType ElementType, SMESH::SMESH_MeshEditor::Extrusion_Error & theError); - SMESH::ListOfGroups* mirror(const SMESH::long_array & IDsOfElements, + SMESH::ListOfGroups* mirror(TIDSortedElemSet & IDsOfElements, const SMESH::AxisStruct & Axis, SMESH::SMESH_MeshEditor::MirrorType MirrorType, CORBA::Boolean Copy, const bool MakeGroups, ::SMESH_Mesh* TargetMesh=0); - SMESH::ListOfGroups* translate(const SMESH::long_array & IDsOfElements, + SMESH::ListOfGroups* translate(TIDSortedElemSet & IDsOfElements, const SMESH::DirStruct & Vector, CORBA::Boolean Copy, const bool MakeGroups, ::SMESH_Mesh* TargetMesh=0); - SMESH::ListOfGroups* rotate(const SMESH::long_array & IDsOfElements, + SMESH::ListOfGroups* rotate(TIDSortedElemSet & IDsOfElements, const SMESH::AxisStruct & Axis, CORBA::Double Angle, CORBA::Boolean Copy, const bool MakeGroups, ::SMESH_Mesh* TargetMesh=0); - SMESH::ListOfGroups* scale(const SMESH::long_array & theIDsOfElements, - const SMESH::PointStruct& thePoint, - const SMESH::double_array& theScaleFact, - CORBA::Boolean theCopy, - const bool theMakeGroups, - ::SMESH_Mesh* theTargetMesh=0); + SMESH::ListOfGroups* scale(SMESH::SMESH_IDSource_ptr theObject, + const SMESH::PointStruct& thePoint, + const SMESH::double_array& theScaleFact, + CORBA::Boolean theCopy, + const bool theMakeGroups, + ::SMESH_Mesh* theTargetMesh=0); SMESH::SMESH_Mesh_ptr makeMesh(const char* theMeshName); void DumpGroupsList(SMESH::TPythonDump & theDumpPython, const SMESH::ListOfGroups * theGroupList); + string generateGroupName(const string& thePrefix); + private: //!< fields SMESH_Mesh_i* myMesh_i; diff --git a/src/SMESH_I/SMESH_Mesh_i.cxx b/src/SMESH_I/SMESH_Mesh_i.cxx index a21535af8..c3be622ae 100644 --- a/src/SMESH_I/SMESH_Mesh_i.cxx +++ b/src/SMESH_I/SMESH_Mesh_i.cxx @@ -19,12 +19,11 @@ // // 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_Mesh_i.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// + #include "SMESH_Mesh_i.hxx" #include "SMESH_Filter_i.hxx" @@ -90,7 +89,9 @@ using SMESH::TPythonDump; int SMESH_Mesh_i::myIdGenerator = 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 //============================================================================= /*! @@ -119,17 +120,48 @@ SMESH_Mesh_i::SMESH_Mesh_i( PortableServer::POA_ptr thePOA, SMESH_Mesh_i::~SMESH_Mesh_i() { INFOS("~SMESH_Mesh_i"); - map::iterator it; - for ( it = _mapGroups.begin(); it != _mapGroups.end(); it++ ) { - SMESH_GroupBase_i* aGroup = dynamic_cast( SMESH_Gen_i::GetServant( it->second ).in() ); - if ( aGroup ) { - // this method is colled from destructor of group (PAL6331) + +#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) //_impl->RemoveGroup( aGroup->GetLocalID() ); - + aGroup->myMeshServant = 0; aGroup->Destroy(); } } _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) { + aSubMesh->Destroy(); + } + } + _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) { + aHypo->Destroy(); + } + } + _mapHypo.clear(); +#endif + delete _impl; } @@ -474,6 +506,9 @@ 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 ); @@ -625,6 +660,9 @@ SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::GetSubMesh(GEOM::GEOM_Object_ptr aSubShap //Get or Create the SMESH_subMesh object implementation int subMeshId = _impl->GetMeshDS()->ShapeToIndex( myLocSubShape ); + if ( !subMeshId && ! _impl->GetMeshDS()->IsGroupOfSubShapes( myLocSubShape )) + THROW_SALOME_CORBA_EXCEPTION("not sub-shape of the main shape", SALOME::BAD_PARAM); + subMesh = getSubMesh( subMeshId ); // create a new subMesh object servant if there is none for the shape @@ -698,6 +736,7 @@ inline TCollection_AsciiString ElementTypeString (SMESH::ElementType theElemType CASE2STRING( EDGE ); CASE2STRING( FACE ); CASE2STRING( VOLUME ); + CASE2STRING( ELEM0D ); default:; } return ""; @@ -819,8 +858,7 @@ void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup SMESH::long_array_var anIds = aGroup->GetListOfID(); SMESH::SMESH_MeshEditor_var aMeshEditor = SMESH_Mesh_i::GetMeshEditor(); - // Update Python script - TPythonDump() << _this() << ".RemoveGroupWithContents( " << theGroup << " )"; + TPythonDump pyDump; // Supress dump from RemoveNodes/Elements() and RemoveGroup() // Remove contents if ( aGroup->GetType() == SMESH::NODE ) @@ -831,12 +869,10 @@ void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup // Remove group RemoveGroup( theGroup ); - // Clear python lines, created by RemoveNodes/Elements() and RemoveGroup() - _gen_i->RemoveLastFromPythonScript(_gen_i->GetCurrentStudy()->StudyId()); - _gen_i->RemoveLastFromPythonScript(_gen_i->GetCurrentStudy()->StudyId()); + // Update Python script + pyDump << _this() << ".RemoveGroupWithContents( " << theGroup << " )"; } - //================================================================================ /*! * \brief Get the list of groups existing in the mesh @@ -879,6 +915,7 @@ SMESH::ListOfGroups * SMESH_Mesh_i::GetGroups() throw(SALOME::SALOME_Exception) return aList._retn(); } + //============================================================================= /*! * Get number of groups existing in the mesh @@ -2071,13 +2108,17 @@ void SMESH_Mesh_i::removeGroup( const int theId ) { if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeGroup()" ); if ( _mapGroups.find( theId ) != _mapGroups.end() ) { - removeGeomGroupData( _mapGroups[theId] ); + SMESH::SMESH_GroupBase_ptr group = _mapGroups[theId]; _mapGroups.erase( theId ); - _impl->RemoveGroup( theId ); + removeGeomGroupData( group ); + if (! _impl->RemoveGroup( theId )) + { + // it seems to be a call up from _impl caused by hyp modification (issue 0020918) + RemoveGroup( group ); + } } } - //============================================================================= /*! * @@ -2174,6 +2215,19 @@ CORBA::Long SMESH_Mesh_i::GetStudyId()throw(SALOME::SALOME_Exception) return _studyId; } +//============================================================================= +namespace +{ + //!< implementation of struct used to call SMESH_Mesh_i::removeGroup() from + // SMESH_Mesh::RemoveGroup() (issue 0020918) + struct TRmGroupCallUp_i : public SMESH_Mesh::TRmGroupCallUp + { + SMESH_Mesh_i* _mesh; + TRmGroupCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {} + virtual void RemoveGroup (const int theGroupID) { _mesh->removeGroup( theGroupID ); } + }; +} + //============================================================================= /*! * @@ -2184,6 +2238,8 @@ void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl) { if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl"); _impl = impl; + if ( _impl ) + _impl->SetRemoveGroupCallUp( new TRmGroupCallUp_i(this)); } //============================================================================= @@ -2360,7 +2416,7 @@ void SMESH_Mesh_i::ExportToMEDX (const char* file, // check names of groups checkGroupNames(); - TPythonDump() << _this() << ".ExportToMEDX( '" + TPythonDump() << _this() << ".ExportToMEDX( r'" << file << "', " << auto_groups << ", " << theVersion << ", " << overwrite << " )"; _impl->ExportMED( file, aMeshName, auto_groups, theVersion ); @@ -2389,7 +2445,7 @@ void SMESH_Mesh_i::ExportDAT (const char *file) // Update Python script // check names of groups checkGroupNames(); - TPythonDump() << _this() << ".ExportDAT( '" << file << "' )"; + TPythonDump() << _this() << ".ExportDAT( r'" << file << "' )"; // Perform Export PrepareForWriting(file); @@ -2404,7 +2460,7 @@ void SMESH_Mesh_i::ExportUNV (const char *file) // Update Python script // check names of groups checkGroupNames(); - TPythonDump() << _this() << ".ExportUNV( '" << file << "' )"; + TPythonDump() << _this() << ".ExportUNV( r'" << file << "' )"; // Perform Export PrepareForWriting(file); @@ -2419,7 +2475,7 @@ void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii) // Update Python script // check names of groups checkGroupNames(); - TPythonDump() << _this() << ".ExportSTL( '" << file << "', " << isascii << " )"; + TPythonDump() << _this() << ".ExportSTL( r'" << file << "', " << isascii << " )"; // Perform Export PrepareForWriting(file); @@ -2749,7 +2805,7 @@ SMESH::long_array* SMESH_Mesh_i::GetNodesId() long nbNodes = NbNodes(); aResult->length( nbNodes ); - SMDS_NodeIteratorPtr anIt = aSMESHDS_Mesh->nodesIterator(); + SMDS_NodeIteratorPtr anIt = aSMESHDS_Mesh->nodesIterator(/*idInceasingOrder=*/true); for ( int i = 0, n = nbNodes; i < n && anIt->more(); i++ ) aResult[i] = anIt->next()->GetID(); @@ -3351,6 +3407,7 @@ void SMESH_Mesh_i::CreateGroupServants() { SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + set addedIDs; ::SMESH_Mesh::GroupIteratorPtr groupIt = _impl->GetGroups(); while ( groupIt->more() ) { @@ -3360,6 +3417,7 @@ void SMESH_Mesh_i::CreateGroupServants() map::iterator it = _mapGroups.find(anId); if ( it != _mapGroups.end() && !CORBA::is_nil( it->second )) continue; + addedIDs.insert( anId ); SMESH_GroupBase_i* aGroupImpl; TopoDS_Shape shape; @@ -3385,12 +3443,23 @@ void SMESH_Mesh_i::CreateGroupServants() int nextId = _gen_i->RegisterObject( groupVar ); if(MYDEBUG) MESSAGE( "Add group to map with id = "<< nextId); - // publishing of the groups in the study + // publishing the groups in the study if ( !aStudy->_is_nil() ) { GEOM::GEOM_Object_var shapeVar = _gen_i->ShapeToGeomObject( shape ); _gen_i->PublishGroup( aStudy, _this(), groupVar, shapeVar, groupVar->GetName()); } } + if ( !addedIDs.empty() ) + { + // python dump + set::iterator id = addedIDs.begin(); + for ( ; id != addedIDs.end(); ++id ) + { + map::iterator it = _mapGroups.find(*id); + int i = std::distance( _mapGroups.begin(), it ); + TPythonDump() << it->second << " = " << _this() << ".GetGroups()[ "<< i << " ]"; + } + } } //============================================================================= @@ -3518,6 +3587,40 @@ SMESH::string_array* SMESH_Mesh_i::GetLastParameters() return aResult._retn(); } +//======================================================================= +//function : GetTypes +//purpose : Returns types of elements it contains +//======================================================================= + +SMESH::array_of_ElementType* SMESH_Mesh_i::GetTypes() +{ + SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType; + + types->length( 4 ); + int nbTypes = 0; + if (_impl->NbEdges()) + types[nbTypes++] = SMESH::EDGE; + if (_impl->NbFaces()) + types[nbTypes++] = SMESH::FACE; + if (_impl->NbVolumes()) + types[nbTypes++] = SMESH::VOLUME; + if (_impl->Nb0DElements()) + types[nbTypes++] = SMESH::ELEM0D; + types->length( nbTypes ); + + return types._retn(); +} + +//======================================================================= +//function : GetMesh +//purpose : Returns self +//======================================================================= + +SMESH::SMESH_Mesh_ptr SMESH_Mesh_i::GetMesh() +{ + return SMESH::SMESH_Mesh::_duplicate( _this() ); +} + //============================================================================= /*! * \brief Returns statistic of mesh elements @@ -3862,10 +3965,9 @@ SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder() */ //============================================================================= -static void findCommonSubMesh - (list& theSubMeshList, - const SMESH_subMesh* theSubMesh, - set& theCommon ) +static void findCommonSubMesh (list& theSubMeshList, + const SMESH_subMesh* theSubMesh, + set& theCommon ) { if ( !theSubMesh ) return; diff --git a/src/SMESH_I/SMESH_Mesh_i.hxx b/src/SMESH_I/SMESH_Mesh_i.hxx index 521633e51..ea33ec9fa 100644 --- a/src/SMESH_I/SMESH_Mesh_i.hxx +++ b/src/SMESH_I/SMESH_Mesh_i.hxx @@ -19,12 +19,11 @@ // // 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_Mesh_i.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// + #ifndef _SMESH_MESH_I_HXX_ #define _SMESH_MESH_I_HXX_ @@ -98,7 +97,7 @@ public: SMESH::SMESH_Group_ptr CreateGroup( SMESH::ElementType theElemType, const char* theName ) throw (SALOME::SALOME_Exception); - + SMESH::SMESH_GroupOnGeom_ptr CreateGroupFromGEOM(SMESH::ElementType theElemType, const char* theName, GEOM::GEOM_Object_ptr theGeomObj ) @@ -106,49 +105,49 @@ public: void RemoveGroup( SMESH::SMESH_GroupBase_ptr theGroup ) throw (SALOME::SALOME_Exception); - + void RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup ) throw (SALOME::SALOME_Exception); - + SMESH::ListOfGroups* GetGroups() throw (SALOME::SALOME_Exception); CORBA::Long NbGroups() throw (SALOME::SALOME_Exception); - SMESH::SMESH_Group_ptr UnionGroups( SMESH::SMESH_GroupBase_ptr theGroup1, - SMESH::SMESH_GroupBase_ptr theGroup2, + SMESH::SMESH_Group_ptr UnionGroups( SMESH::SMESH_GroupBase_ptr theGroup1, + SMESH::SMESH_GroupBase_ptr theGroup2, const char* theName ) throw (SALOME::SALOME_Exception); - SMESH::SMESH_Group_ptr UnionListOfGroups( const SMESH::ListOfGroups& theGroups, + SMESH::SMESH_Group_ptr UnionListOfGroups( const SMESH::ListOfGroups& theGroups, const char* theName) throw (SALOME::SALOME_Exception); - - SMESH::SMESH_Group_ptr IntersectGroups( SMESH::SMESH_GroupBase_ptr theGroup1, - SMESH::SMESH_GroupBase_ptr theGroup2, + + SMESH::SMESH_Group_ptr IntersectGroups( SMESH::SMESH_GroupBase_ptr theGroup1, + SMESH::SMESH_GroupBase_ptr theGroup2, const char* theName ) throw (SALOME::SALOME_Exception); - SMESH::SMESH_Group_ptr IntersectListOfGroups( const SMESH::ListOfGroups& theGroups, + SMESH::SMESH_Group_ptr IntersectListOfGroups( const SMESH::ListOfGroups& theGroups, const char* theName ) throw (SALOME::SALOME_Exception); - - SMESH::SMESH_Group_ptr CutGroups( SMESH::SMESH_GroupBase_ptr theGroup1, - SMESH::SMESH_GroupBase_ptr theGroup2, + + SMESH::SMESH_Group_ptr CutGroups( SMESH::SMESH_GroupBase_ptr theGroup1, + SMESH::SMESH_GroupBase_ptr theGroup2, const char* theName ) throw (SALOME::SALOME_Exception); - SMESH::SMESH_Group_ptr CutListOfGroups( const SMESH::ListOfGroups& theMainGroups, - const SMESH::ListOfGroups& theToolGroups, + SMESH::SMESH_Group_ptr CutListOfGroups( const SMESH::ListOfGroups& theMainGroups, + const SMESH::ListOfGroups& theToolGroups, const char* theName ) throw (SALOME::SALOME_Exception); - SMESH::SMESH_Group_ptr CreateDimGroup( const SMESH::ListOfGroups& theGroups, - SMESH::ElementType theElemType, + SMESH::SMESH_Group_ptr CreateDimGroup( const SMESH::ListOfGroups& theGroups, + SMESH::ElementType theElemType, const char* theName ) throw (SALOME::SALOME_Exception); - + SMESH::SMESH_Group_ptr ConvertToStandalone( SMESH::SMESH_GroupOnGeom_ptr theGeomGroup ); @@ -303,16 +302,16 @@ public: SMESH::long_array* GetElementsByType( SMESH::ElementType theElemType ) throw (SALOME::SALOME_Exception); - + SMESH::long_array* GetNodesId() throw (SALOME::SALOME_Exception); - + SMESH::ElementType GetElementType( CORBA::Long id, bool iselem ) throw (SALOME::SALOME_Exception); - + SMESH::EntityType GetElementGeomType( CORBA::Long id ) throw (SALOME::SALOME_Exception); - + /*! * Returns ID of elements for given submesh */ @@ -326,15 +325,15 @@ public: */ SMESH::long_array* GetSubMeshNodesId(CORBA::Long ShapeID, CORBA::Boolean all) throw (SALOME::SALOME_Exception); - + /*! * Returns type of elements for given submesh */ SMESH::ElementType GetSubMeshElementType(CORBA::Long ShapeID) throw (SALOME::SALOME_Exception); - + char* Dump(); - + // Internal methods not available through CORBA // They are called by corresponding interface methods SMESH_Hypothesis::Hypothesis_Status addHypothesis(GEOM::GEOM_Object_ptr aSubShapeObject, @@ -342,7 +341,7 @@ public: SMESH_Hypothesis::Hypothesis_Status removeHypothesis(GEOM::GEOM_Object_ptr aSubShapeObject, SMESH::SMESH_Hypothesis_ptr anHyp); - + static SMESH::Hypothesis_Status ConvertHypothesisStatus (SMESH_Hypothesis::Hypothesis_Status theStatus); @@ -369,13 +368,11 @@ public: /*! * \brief Update hypotheses assigned to geom groups if the latter change - * + * * NPAL16168: "geometrical group edition from a submesh don't modifiy mesh computation" */ void CheckGeomGroupModif(); - virtual SMESH::long_array* GetIDs(); - CORBA::LongLong GetMeshPtr(); /*! @@ -393,7 +390,7 @@ public: * If there is not node for given ID - returns empty list */ SMESH::double_array* GetNodeXYZ(CORBA::Long id); - + /*! * For given node returns list of IDs of inverse elements * If there is not node for given ID - returns empty list @@ -412,7 +409,7 @@ public: CORBA::Long GetShapeID(CORBA::Long id); /*! - * For given element returns ID of result shape after + * For given element returns ID of result shape after * ::FindShape() from SMESH_MeshEditor * If there is not element for given ID - returns -1 */ @@ -435,25 +432,25 @@ public: * If there is not node for given index - returns -2 */ CORBA::Long GetElemNode(CORBA::Long id, CORBA::Long index); - + /*! * Returns true if given node is medium node * in given quadratic element */ CORBA::Boolean IsMediumNode(CORBA::Long ide, CORBA::Long idn); - + /*! * Returns true if given node is medium node * in one of quadratic elements */ CORBA::Boolean IsMediumNodeOfAnyElem(CORBA::Long idn, SMESH::ElementType theElemType); - + /*! * Returns number of edges for given element */ CORBA::Long ElemNbEdges(CORBA::Long id); - + /*! * Returns number of faces for given element */ @@ -472,12 +469,12 @@ public: * Returns true if given element is polygon */ CORBA::Boolean IsPoly(CORBA::Long id); - + /*! * Returns true if given element is quadratic */ CORBA::Boolean IsQuadratic(CORBA::Long id); - + /*! * Returns bary center for given element */ @@ -492,7 +489,7 @@ public: * Sets list of notebook variables used for Mesh operations separated by ":" symbol */ void SetParameters (const char* theParameters); - + /*! * Returns list of notebook variables used for Mesh operations separated by ":" symbol */ @@ -503,20 +500,11 @@ public: */ SMESH::string_array* GetLastParameters(); - - /*! - * Returns statistic of mesh elements - * Result array of number enityties - * Inherited from SMESH_IDSource - */ - virtual SMESH::long_array* GetMeshInfo(); - /*! * Collect statistic of mesh elements given by iterator */ static void CollectMeshInfo(const SMDS_ElemIteratorPtr theItr, SMESH::long_array& theInfo); - /*! * \brief Return submesh objects list in meshing order @@ -527,7 +515,28 @@ public: */ virtual ::CORBA::Boolean SetMeshOrder(const SMESH::submesh_array_array& theSubMeshArray); - + + // ========================= + // SMESH_IDSource interface + // ========================= + + virtual SMESH::long_array* GetIDs(); + /*! + * Returns statistic of mesh elements + * Result array of number enityties + * Inherited from SMESH_IDSource + */ + virtual SMESH::long_array* GetMeshInfo(); + /*! + * Returns types of elements it contains + */ + virtual SMESH::array_of_ElementType* GetTypes(); + /*! + * Returns self + */ + virtual SMESH::SMESH_Mesh_ptr GetMesh(); + + std::map _mapSubMesh_i; //NRI std::map _mapSubMesh; //NRI @@ -581,8 +590,7 @@ private: * \brief Return new group contents if it has been changed and update group data */ TopoDS_Shape newGroupShape( TGeomGroupData & groupData); - + }; #endif - diff --git a/src/SMESH_I/SMESH_Pattern_i.cxx b/src/SMESH_I/SMESH_Pattern_i.cxx index 3d725b8fb..2a799a5b6 100644 --- a/src/SMESH_I/SMESH_Pattern_i.cxx +++ b/src/SMESH_I/SMESH_Pattern_i.cxx @@ -387,7 +387,14 @@ CORBA::Boolean SMESH_Pattern_i::MakeMesh (SMESH::SMESH_Mesh_ptr theMesh, << CreatePolygons << ", " << CreatePolyedrs << " )"; addErrorCode( "MakeMesh" ); - return myPattern.MakeMesh( aMesh, CreatePolygons, CreatePolyedrs ); + int nb = aMesh->NbNodes() + aMesh->NbEdges() + aMesh->NbFaces() + aMesh->NbVolumes(); + + bool res = myPattern.MakeMesh( aMesh, CreatePolygons, CreatePolyedrs ); + + if ( nb > 0 && nb != aMesh->NbNodes() + aMesh->NbEdges() + aMesh->NbFaces() + aMesh->NbVolumes()) + aMesh->SetIsModified(true); + + return res; } //======================================================================= diff --git a/src/SMESH_I/SMESH_PythonDump.hxx b/src/SMESH_I/SMESH_PythonDump.hxx index afcd15ddb..f1ee26581 100644 --- a/src/SMESH_I/SMESH_PythonDump.hxx +++ b/src/SMESH_I/SMESH_PythonDump.hxx @@ -73,6 +73,7 @@ namespace SMESH class FilterManager_i; class Filter_i; class Functor_i; + class Measurements_i; // =========================================================================================== /*! @@ -142,6 +143,9 @@ namespace SMESH TPythonDump& operator<<(SMESH::Functor_i* theArg); + TPythonDump& + operator<<(SMESH::Measurements_i* theArg); + TPythonDump& operator<<(SMESH_Gen_i* theArg); @@ -161,7 +165,10 @@ namespace SMESH operator<<(const TCollection_AsciiString & theArg); TPythonDump& - operator<<(const SMESH::ListOfGroups * theList); + operator<<(const SMESH::ListOfGroups& theList); + + TPythonDump& + operator<<(const SMESH::ListOfIDSources& theList); static const char* SMESHGenName() { return "smeshgen"; } static const char* MeshEditorName() { return "mesh_editor"; } diff --git a/src/SMESH_I/SMESH_subMesh_i.cxx b/src/SMESH_I/SMESH_subMesh_i.cxx index 301f1a972..45d486733 100644 --- a/src/SMESH_I/SMESH_subMesh_i.cxx +++ b/src/SMESH_I/SMESH_subMesh_i.cxx @@ -545,3 +545,46 @@ SMESH::long_array* SMESH_subMesh_i::GetMeshInfo() return aRes._retn(); } + + +//======================================================================= +//function : GetTypes +//purpose : Returns types of elements it contains +//======================================================================= + +SMESH::array_of_ElementType* SMESH_subMesh_i::GetTypes() +{ + SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType; + + ::SMESH_subMesh* aSubMesh = _mesh_i->_mapSubMesh[_localId]; + TopoDS_Shape shape = aSubMesh->GetSubShape(); + while ( !shape.IsNull() && shape.ShapeType() == TopAbs_COMPOUND ) + { + TopoDS_Iterator it( shape ); + shape = it.More() ? it.Value() : TopoDS_Shape(); + } + if ( !shape.IsNull() ) + { + types->length( 1 ); + switch ( ::SMESH_Gen::GetShapeDim( shape )) + { + case 0: types[0] = SMESH::ELEM0D; break; + case 1: types[0] = SMESH::EDGE; break; + case 2: types[0] = SMESH::FACE; break; + case 3: types[0] = SMESH::VOLUME; break; + default: + types->length(0); + } + } + return types._retn(); +} + +//======================================================================= +//function : GetMesh +//purpose : interface SMESH_IDSource +//======================================================================= + +SMESH::SMESH_Mesh_ptr SMESH_subMesh_i::GetMesh() +{ + return GetFather(); +} diff --git a/src/SMESH_I/SMESH_subMesh_i.hxx b/src/SMESH_I/SMESH_subMesh_i.hxx index bd53171ae..f5fd559d4 100644 --- a/src/SMESH_I/SMESH_subMesh_i.hxx +++ b/src/SMESH_I/SMESH_subMesh_i.hxx @@ -85,14 +85,29 @@ public: SALOME_MED::FAMILY_ptr GetFamily() throw (SALOME::SALOME_Exception); - virtual SMESH::long_array* GetIDs(); + // ========================= + // interface SMESH_IDSource + // ========================= + /*! + * Returns a sequence of all element IDs + */ + virtual SMESH::long_array* GetIDs(); /*! * Returns statistic of mesh elements * Result array of number enityties * Inherited from SMESH_IDSource */ virtual SMESH::long_array* GetMeshInfo(); + /*! + * Returns types of elements it contains + */ + virtual SMESH::array_of_ElementType* GetTypes(); + /*! + * Returns the mesh + */ + SMESH::SMESH_Mesh_ptr GetMesh(); + SMESH_Mesh_i* _mesh_i; //NRI diff --git a/src/SMESH_PY/Makefile.am b/src/SMESH_PY/Makefile.am new file mode 100644 index 000000000..254e9ef08 --- /dev/null +++ b/src/SMESH_PY/Makefile.am @@ -0,0 +1,25 @@ +# Copyright (C) 2007-2010 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 +# + +include $(top_srcdir)/adm_local/unix/make_common_starter.am + +salomepypkgdir = $(salomepythondir)/salome/smesh +salomepypkg_PYTHON = \ + __init__.py \ + smeshstudytools.py diff --git a/src/SMESH_PY/__init__.py b/src/SMESH_PY/__init__.py new file mode 100644 index 000000000..5d3edfa55 --- /dev/null +++ b/src/SMESH_PY/__init__.py @@ -0,0 +1 @@ +# -*- coding: iso-8859-1 -*- diff --git a/src/SMESH_PY/smeshstudytools.py b/src/SMESH_PY/smeshstudytools.py new file mode 100644 index 000000000..0545efae6 --- /dev/null +++ b/src/SMESH_PY/smeshstudytools.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007-2009 EDF R&D +# +# This file is part of PAL_SRC. +# +# PAL_SRC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PAL_SRC 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with PAL_SRC; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +""" +This module provides a new class :class:`SMeshStudyTools` to facilitate the +use of mesh objects in Salome study. +""" + +import salome +SMESH = None # SMESH module is loaded only when needed + +from salome.kernel.studyedit import getStudyEditor + +class SMeshStudyTools: + """ + This class provides several methods to manipulate mesh objects in Salome + study. The parameter `studyEditor` defines a + :class:`~salome.kernel.studyedit.StudyEditor` object used to access the study. If + :const:`None`, the method returns a :class:`~salome.kernel.studyedit.StudyEditor` + object on the current study. + + .. attribute:: editor + + This instance attribute contains the underlying + :class:`~salome.kernel.studyedit.StudyEditor` object. It can be used to access + the study but the attribute itself should not be modified. + + """ + + def __init__(self, studyEditor = None): + global SMESH + if SMESH is None: + SMESH = __import__("SMESH") + if studyEditor is None: + studyEditor = getStudyEditor() + self.editor = studyEditor + + def getMeshFromGroup(self, meshGroupItem): + """ + Get the mesh item owning the mesh group `meshGroupItem`. + + :type meshGroupItem: SObject + :param meshGroupItem: Mesh group belonging to the searched mesh. + + :return: The SObject corresponding to the mesh, or None if it was not + found. + """ + meshItem = None + obj = self.editor.getOrLoadObject(meshGroupItem) + group = obj._narrow(SMESH.SMESH_GroupBase) + if group is not None: # The type of the object is ok + meshObj = group.GetMesh() + meshItem = salome.ObjectToSObject(meshObj) + return meshItem diff --git a/src/SMESH_SWIG/SMESH_BelongToGeom.py b/src/SMESH_SWIG/SMESH_BelongToGeom.py index 02047a1cf..af6c98420 100644 --- a/src/SMESH_SWIG/SMESH_BelongToGeom.py +++ b/src/SMESH_SWIG/SMESH_BelongToGeom.py @@ -40,6 +40,7 @@ def CheckBelongToGeomFilterOld(theMeshGen, theMesh, theShape, theSubShape, theEl aBelongToGeom.SetElementType(theElemType) aFilter.SetPredicate(aBelongToGeom) + aFilterMgr.Destroy() return aFilter.GetElementsId(theMesh) ## Current style diff --git a/src/SMESH_SWIG/SMESH_GroupLyingOnGeom.py b/src/SMESH_SWIG/SMESH_GroupLyingOnGeom.py index e0cbb6404..c90a3bd89 100644 --- a/src/SMESH_SWIG/SMESH_GroupLyingOnGeom.py +++ b/src/SMESH_SWIG/SMESH_GroupLyingOnGeom.py @@ -36,6 +36,7 @@ def BuildGroupLyingOn(theMesh, theElemType, theName, theShape): aFilter.SetPredicate(aLyingOnGeom) anIds = aFilter.GetElementsId(theMesh) + aFilterMgr.Destroy() aGroup = theMesh.CreateGroup(theElemType, theName) aGroup.Add(anIds) diff --git a/src/SMESH_SWIG/SMESH_Nut.py b/src/SMESH_SWIG/SMESH_Nut.py index 801e554f1..62b6af8b9 100755 --- a/src/SMESH_SWIG/SMESH_Nut.py +++ b/src/SMESH_SWIG/SMESH_Nut.py @@ -87,7 +87,7 @@ geompy.addToStudy(Chamfer_2, "Chamfer_2") #Import of the shape from "slots.brep" print "Import multi-rotation from the DATA_DIR/Shapes/Brep/slots.brep" thePath = os.getenv("DATA_DIR") -theFileName = thePath + "/Shapes/Brep/slots.brep" +theFileName = os.path.join( thePath,"Shapes","Brep","slots.brep") theShapeForCut = geompy.ImportBREP(theFileName) geompy.addToStudy(theShapeForCut, "slot.brep_1") diff --git a/src/SMESH_SWIG/SMESH_controls.py b/src/SMESH_SWIG/SMESH_controls.py index 43c1b5874..a322e42c5 100644 --- a/src/SMESH_SWIG/SMESH_controls.py +++ b/src/SMESH_SWIG/SMESH_controls.py @@ -128,4 +128,16 @@ print "Criterion: Borders at multi-connections = 2 Nb = ", len( anIds ) #print anIds[ i ] +# Criterion : Element Diameter 2D > 10 + +# create group +aGroup = mesh.MakeGroup("Element Diameter 2D > 10", smesh.FACE, smesh.FT_MaxElementLength2D, smesh.FT_MoreThan, 10 ) + +# print result +anIds = aGroup.GetIDs() +print "Criterion: Element Diameter 2D > 10 Nb = ", len( anIds ) +#for i in range( len( anIds ) ): + #print anIds[ i ] + + salome.sg.updateObjBrowser(1) diff --git a/src/SMESH_SWIG/smeshDC.py b/src/SMESH_SWIG/smeshDC.py index de8f32624..a2476107a 100644 --- a/src/SMESH_SWIG/smeshDC.py +++ b/src/SMESH_SWIG/smeshDC.py @@ -50,6 +50,7 @@ ## @defgroup l3_hypos_ghs3dh GHS3D Parameters hypothesis ## @defgroup l3_hypos_blsurf BLSURF Parameters hypothesis ## @defgroup l3_hypos_hexotic Hexotic Parameters hypothesis +## @defgroup l3_hypos_quad Quadrangle Parameters hypothesis ## @defgroup l3_hypos_additi Additional Hypotheses ## @} @@ -87,6 +88,7 @@ ## @defgroup l2_modif_tofromqu Convert to/from Quadratic Mesh ## @} +## @defgroup l1_measurements Measurements import salome import geompyDC @@ -198,6 +200,11 @@ PrecisionConfusion = 1e-07 # TopAbs_State enumeration [TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN] = range(4) +# Methods of splitting a hexahedron into tetrahedra +Hex_5Tet, Hex_6Tet, Hex_24Tet = 1, 2, 3 + +# import items of enum QuadType +for e in StdMeshers.QuadType._items: exec('%s = StdMeshers.%s'%(e,e)) ## Converts an angle from degrees to radians def DegreesToRadians(AngleInDegrees): @@ -513,6 +520,20 @@ class smeshDC(SMESH._objref_SMESH_Gen): def EnumToLong(self,theItem): return theItem._v + ## Returns a string representation of the color. + # To be used with filters. + # @param c color value (SALOMEDS.Color) + # @ingroup l1_controls + def ColorToString(self,c): + val = "" + if isinstance(c, SALOMEDS.Color): + val = "%s;%s;%s" % (c.R, c.G, c.B) + elif isinstance(c, str): + val = c + else: + raise ValueError, "Color value should be of string or SALOMEDS.Color type" + return val + ## Gets PointStruct from vertex # @param theVertex a GEOM object(vertex) # @return SMESH.PointStruct @@ -673,6 +694,9 @@ class smeshDC(SMESH._objref_SMESH_Gen): def Concatenate( self, meshes, uniteIdenticalGroups, mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False): mergeTolerance,Parameters = geompyDC.ParseParameters(mergeTolerance) + for i,m in enumerate(meshes): + if isinstance(m, Mesh): + meshes[i] = m.GetMesh() if allGroups: aSmeshMesh = SMESH._objref_SMESH_Gen.ConcatenateWithGroups( self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance) @@ -753,8 +777,40 @@ class smeshDC(SMESH._objref_SMESH_Gen): else: print "Error: The treshold should be a string." return None + elif CritType == FT_CoplanarFaces: + # Checks the treshold + if isinstance(aTreshold, int): + aCriterion.ThresholdID = "%s"%aTreshold + elif isinstance(aTreshold, str): + ID = int(aTreshold) + if ID < 1: + raise ValueError, "Invalid ID of mesh face: '%s'"%aTreshold + aCriterion.ThresholdID = aTreshold + else: + raise ValueError,\ + "The treshold should be an ID of mesh face and not '%s'"%aTreshold + elif CritType == FT_ElemGeomType: + # Checks the treshold + try: + aCriterion.Threshold = self.EnumToLong(aTreshold) + except: + if isinstance(aTreshold, int): + aCriterion.Threshold = aTreshold + else: + print "Error: The treshold should be an integer or SMESH.GeometryType." + return None + pass + pass + elif CritType == FT_GroupColor: + # Checks the treshold + try: + aCriterion.ThresholdStr = self.ColorToString(aTreshold) + except: + print "Error: The threshold value should be of SALOMEDS.Color type" + return None + pass elif CritType in [FT_FreeBorders, FT_FreeEdges, FT_BadOrientedVolume, FT_FreeNodes, - FT_FreeFaces, FT_ElemGeomType, FT_GroupColor]: + FT_FreeFaces, FT_LinearOrQuadratic]: # At this point the treshold is unnecessary if aTreshold == FT_LogicalNOT: aCriterion.UnaryOp = self.EnumToLong(FT_LogicalNOT) @@ -802,6 +858,7 @@ class smeshDC(SMESH._objref_SMESH_Gen): aCriteria = [] aCriteria.append(aCriterion) aFilter.SetCriteria(aCriteria) + aFilterMgr.Destroy() return aFilter ## Creates a numerical functor by its type @@ -826,6 +883,10 @@ class smeshDC(SMESH._objref_SMESH_Gen): return aFilterMgr.CreateArea() elif theCriterion == FT_Volume3D: return aFilterMgr.CreateVolume3D() + elif theCriterion == FT_MaxElementLength2D: + return aFilterMgr.CreateMaxElementLength2D() + elif theCriterion == FT_MaxElementLength3D: + return aFilterMgr.CreateMaxElementLength3D() elif theCriterion == FT_MultiConnection: return aFilterMgr.CreateMultiConnection() elif theCriterion == FT_MultiConnection2D: @@ -858,6 +919,110 @@ class smeshDC(SMESH._objref_SMESH_Gen): pass return d + ## Get minimum distance between two objects + # + # If @a src2 is None, and @a id2 = 0, distance from @a src1 / @a id1 to the origin is computed. + # If @a src2 is None, and @a id2 != 0, it is assumed that both @a id1 and @a id2 belong to @a src1. + # + # @param src1 first source object + # @param src2 second source object + # @param id1 node/element id from the first source + # @param id2 node/element id from the second (or first) source + # @param isElem1 @c True if @a id1 is element id, @c False if it is node id + # @param isElem2 @c True if @a id2 is element id, @c False if it is node id + # @return minimum distance value + # @sa GetMinDistance() + # @ingroup l1_measurements + def MinDistance(self, src1, src2=None, id1=0, id2=0, isElem1=False, isElem2=False): + result = self.GetMinDistance(src1, src2, id1, id2, isElem1, isElem2) + if result is None: + result = 0.0 + else: + result = result.value + return result + + ## Get measure structure specifying minimum distance data between two objects + # + # If @a src2 is None, and @a id2 = 0, distance from @a src1 / @a id1 to the origin is computed. + # If @a src2 is None, and @a id2 != 0, it is assumed that both @a id1 and @a id2 belong to @a src1. + # + # @param src1 first source object + # @param src2 second source object + # @param id1 node/element id from the first source + # @param id2 node/element id from the second (or first) source + # @param isElem1 @c True if @a id1 is element id, @c False if it is node id + # @param isElem2 @c True if @a id2 is element id, @c False if it is node id + # @return Measure structure or None if input data is invalid + # @sa MinDistance() + # @ingroup l1_measurements + def GetMinDistance(self, src1, src2=None, id1=0, id2=0, isElem1=False, isElem2=False): + if isinstance(src1, Mesh): src1 = src1.mesh + if isinstance(src2, Mesh): src2 = src2.mesh + if src2 is None and id2 != 0: src2 = src1 + if not hasattr(src1, "_narrow"): return None + src1 = src1._narrow(SMESH.SMESH_IDSource) + if not src1: return None + if id1 != 0: + m = src1.GetMesh() + e = m.GetMeshEditor() + if isElem1: + src1 = e.MakeIDSource([id1], SMESH.FACE) + else: + src1 = e.MakeIDSource([id1], SMESH.NODE) + pass + if hasattr(src2, "_narrow"): + src2 = src2._narrow(SMESH.SMESH_IDSource) + if src2 and id2 != 0: + m = src2.GetMesh() + e = m.GetMeshEditor() + if isElem2: + src2 = e.MakeIDSource([id2], SMESH.FACE) + else: + src2 = e.MakeIDSource([id2], SMESH.NODE) + pass + pass + aMeasurements = self.CreateMeasurements() + result = aMeasurements.MinDistance(src1, src2) + aMeasurements.Destroy() + return result + + ## Get bounding box of the specified object(s) + # @param objects single source object or list of source objects + # @return tuple of six values (minX, minY, minZ, maxX, maxY, maxZ) + # @sa GetBoundingBox() + # @ingroup l1_measurements + def BoundingBox(self, objects): + result = self.GetBoundingBox(objects) + if result is None: + result = (0.0,)*6 + else: + result = (result.minX, result.minY, result.minZ, result.maxX, result.maxY, result.maxZ) + return result + + ## Get measure structure specifying bounding box data of the specified object(s) + # @param objects single source object or list of source objects + # @return Measure structure + # @sa BoundingBox() + # @ingroup l1_measurements + def GetBoundingBox(self, objects): + if isinstance(objects, tuple): + objects = list(objects) + if not isinstance(objects, list): + objects = [objects] + srclist = [] + for o in objects: + if isinstance(o, Mesh): + srclist.append(o.mesh) + elif hasattr(o, "_narrow"): + src = o._narrow(SMESH.SMESH_IDSource) + if src: srclist.append(src) + pass + pass + aMeasurements = self.CreateMeasurements() + result = aMeasurements.BoundingBox(srclist) + aMeasurements.Destroy() + return result + import omniORB #Registering the new proxy for SMESH_Gen omniORB.registerObjref(SMESH._objref_SMESH_Gen._NP_RepositoryId, smeshDC) @@ -1023,6 +1188,24 @@ class Mesh: else: return Mesh_Segment(self, geom) + ## Creates 1D algorithm importing segments conatined in groups of other mesh. + # If the optional \a geom parameter is not set, this algorithm is global. + # Otherwise, this algorithm defines a submesh based on \a geom subshape. + # @param geom If defined the subshape is to be meshed + # @return an instance of Mesh_UseExistingElements class + # @ingroup l3_algos_basic + def UseExisting1DElements(self, geom=0): + return Mesh_UseExistingElements(1,self, geom) + + ## Creates 2D algorithm importing faces conatined in groups of other mesh. + # If the optional \a geom parameter is not set, this algorithm is global. + # Otherwise, this algorithm defines a submesh based on \a geom subshape. + # @param geom If defined the subshape is to be meshed + # @return an instance of Mesh_UseExistingElements class + # @ingroup l3_algos_basic + def UseExisting2DElements(self, geom=0): + return Mesh_UseExistingElements(2,self, geom) + ## Enables creation of nodes and segments usable by 2D algoritms. # The added nodes and segments must be bound to edges and vertices by # SetNodeOnVertex(), SetNodeOnEdge() and SetMeshElementOnShape() @@ -1154,7 +1337,9 @@ class Mesh: return Mesh_RadialPrism3D(self, geom) ## Evaluates size of prospective mesh on a shape - # @return True or False + # @return a list where i-th element is a number of elements of i-th SMESH.EntityType + # To know predicted number of e.g. edges, inquire it this way + # Evaluate()[ EnumToLong( Entity_Edge )] def Evaluate(self, geom=0): if geom == 0 or not isinstance(geom, geompyDC.GEOM._objref_GEOM_Object): if self.geom == 0: @@ -1165,6 +1350,7 @@ class Mesh: ## Computes the mesh and returns the status of the computation + # @param geom geomtrical shape on which mesh data should be computed # @param discardModifs if True and the mesh has been edited since # a last total re-compute and that may prevent successful partial re-compute, # then the mesh is cleaned before Compute() @@ -1583,6 +1769,7 @@ class Mesh: aCriteria.append(Criterion) aFilter.SetCriteria(aCriteria) group = self.MakeGroupByFilter(groupName, aFilter) + aFilterMgr.Destroy() return group ## Creates a mesh group by the given criteria (list of criteria) @@ -1595,6 +1782,7 @@ class Mesh: aFilter = aFilterMgr.CreateFilter() aFilter.SetCriteria(theCriteria) group = self.MakeGroupByFilter(groupName, aFilter) + aFilterMgr.Destroy() return group ## Creates a mesh group by the given filter @@ -1603,9 +1791,9 @@ class Mesh: # @return SMESH_Group # @ingroup l2_grps_create def MakeGroupByFilter(self, groupName, theFilter): - anIds = theFilter.GetElementsId(self.mesh) - anElemType = theFilter.GetElementType() - group = self.MakeGroupByIds(groupName, anElemType, anIds) + group = self.CreateEmptyGroup(theFilter.GetElementType(), groupName) + theFilter.SetMesh( self.mesh ) + group.AddFrom( theFilter ) return group ## Passes mesh elements through the given filter and return IDs of fitting elements @@ -1613,7 +1801,8 @@ class Mesh: # @return a list of ids # @ingroup l1_controls def GetIdsFromFilter(self, theFilter): - return theFilter.GetElementsId(self.mesh) + theFilter.SetMesh( self.mesh ) + return theFilter.GetIDs() ## Verifies whether a 2D mesh element has free edges (edges connected to one face only)\n # Returns a list of special structures (borders). @@ -1624,6 +1813,7 @@ class Mesh: aPredicate = aFilterMgr.CreateFreeEdges() aPredicate.SetMesh(self.mesh) aBorders = aPredicate.GetBorders() + aFilterMgr.Destroy() return aBorders ## Removes a group @@ -1965,7 +2155,7 @@ class Mesh: return self.mesh.GetElementsId() ## Returns the list of IDs of mesh elements with the given type - # @param elementType the required type of elements + # @param elementType the required type of elements (SMESH.NODE, SMESH.EDGE, SMESH.FACE or SMESH.VOLUME) # @return list of integer values # @ingroup l1_meshinfo def GetElementsByType(self, elementType): @@ -2143,6 +2333,95 @@ class Mesh: return self.mesh.BaryCenter(id) + # Get mesh measurements information: + # ------------------------------------ + + ## Get minimum distance between two nodes, elements or distance to the origin + # @param id1 first node/element id + # @param id2 second node/element id (if 0, distance from @a id1 to the origin is computed) + # @param isElem1 @c True if @a id1 is element id, @c False if it is node id + # @param isElem2 @c True if @a id2 is element id, @c False if it is node id + # @return minimum distance value + # @sa GetMinDistance() + def MinDistance(self, id1, id2=0, isElem1=False, isElem2=False): + aMeasure = self.GetMinDistance(id1, id2, isElem1, isElem2) + return aMeasure.value + + ## Get measure structure specifying minimum distance data between two objects + # @param id1 first node/element id + # @param id2 second node/element id (if 0, distance from @a id1 to the origin is computed) + # @param isElem1 @c True if @a id1 is element id, @c False if it is node id + # @param isElem2 @c True if @a id2 is element id, @c False if it is node id + # @return Measure structure + # @sa MinDistance() + def GetMinDistance(self, id1, id2=0, isElem1=False, isElem2=False): + if isElem1: + id1 = self.editor.MakeIDSource([id1], SMESH.FACE) + else: + id1 = self.editor.MakeIDSource([id1], SMESH.NODE) + if id2 != 0: + if isElem2: + id2 = self.editor.MakeIDSource([id2], SMESH.FACE) + else: + id2 = self.editor.MakeIDSource([id2], SMESH.NODE) + pass + else: + id2 = None + + aMeasurements = self.smeshpyD.CreateMeasurements() + aMeasure = aMeasurements.MinDistance(id1, id2) + aMeasurements.Destroy() + return aMeasure + + ## Get bounding box of the specified object(s) + # @param objects single source object or list of source objects or list of nodes/elements IDs + # @param isElem if @a objects is a list of IDs, @c True value in this parameters specifies that @a objects are elements, + # @c False specifies that @a objects are nodes + # @return tuple of six values (minX, minY, minZ, maxX, maxY, maxZ) + # @sa GetBoundingBox() + def BoundingBox(self, objects=None, isElem=False): + result = self.GetBoundingBox(objects, isElem) + if result is None: + result = (0.0,)*6 + else: + result = (result.minX, result.minY, result.minZ, result.maxX, result.maxY, result.maxZ) + return result + + ## Get measure structure specifying bounding box data of the specified object(s) + # @param objects single source object or list of source objects or list of nodes/elements IDs + # @param isElem if @a objects is a list of IDs, @c True value in this parameters specifies that @a objects are elements, + # @c False specifies that @a objects are nodes + # @return Measure structure + # @sa BoundingBox() + def GetBoundingBox(self, IDs=None, isElem=False): + if IDs is None: + IDs = [self.mesh] + elif isinstance(IDs, tuple): + IDs = list(IDs) + if not isinstance(IDs, list): + IDs = [IDs] + if len(IDs) > 0 and isinstance(IDs[0], int): + IDs = [IDs] + srclist = [] + for o in IDs: + if isinstance(o, Mesh): + srclist.append(o.mesh) + elif hasattr(o, "_narrow"): + src = o._narrow(SMESH.SMESH_IDSource) + if src: srclist.append(src) + pass + elif isinstance(o, list): + if isElem: + srclist.append(self.editor.MakeIDSource(o, SMESH.FACE)) + else: + srclist.append(self.editor.MakeIDSource(o, SMESH.NODE)) + pass + pass + aMeasurements = self.smeshpyD.CreateMeasurements() + aMeasure = aMeasurements.BoundingBox(srclist) + aMeasurements.Destroy() + return aMeasure + # Mesh edition (SMESH_MeshEditor functionality): # --------------------------------------------- @@ -2160,6 +2439,12 @@ class Mesh: def RemoveNodes(self, IDsOfNodes): return self.editor.RemoveNodes(IDsOfNodes) + ## Removes all orphan (free) nodes from mesh + # @return number of the removed nodes + # @ingroup l2_modif_del + def RemoveOrphanNodes(self): + return self.editor.RemoveOrphanNodes() + ## Add a node to the mesh by coordinates # @return Id of the new node # @ingroup l2_modif_add @@ -2180,7 +2465,7 @@ class Mesh: # @param IDsOfNodes the list of node IDs for creation of the element. # The order of nodes in this list should correspond to the description # of MED. \n This description is located by the following link: - # http://www.salome-platform.org/salome2/web_med_internet/logiciels/medV2.2.2_doc_html/html/modele_de_donnees.html#3. + # http://www.code-aster.org/outils/med/html/modele_de_donnees.html#3. # @return the Id of the new edge # @ingroup l2_modif_add def AddEdge(self, IDsOfNodes): @@ -2191,7 +2476,7 @@ class Mesh: # @param IDsOfNodes the list of node IDs for creation of the element. # The order of nodes in this list should correspond to the description # of MED. \n This description is located by the following link: - # http://www.salome-platform.org/salome2/web_med_internet/logiciels/medV2.2.2_doc_html/html/modele_de_donnees.html#3. + # http://www.code-aster.org/outils/med/html/modele_de_donnees.html#3. # @return the Id of the new face # @ingroup l2_modif_add def AddFace(self, IDsOfNodes): @@ -2209,7 +2494,7 @@ class Mesh: # @param IDsOfNodes the list of node IDs for creation of the element. # The order of nodes in this list should correspond to the description # of MED. \n This description is located by the following link: - # http://www.salome-platform.org/salome2/web_med_internet/logiciels/medV2.2.2_doc_html/html/modele_de_donnees.html#3. + # http://www.code-aster.org/outils/med/html/modele_de_donnees.html#3. # @return the Id of the new volumic element # @ingroup l2_modif_add def AddVolume(self, IDsOfNodes): @@ -2506,13 +2791,14 @@ class Mesh: ## Splits volumic elements into tetrahedrons # @param elemIDs either list of elements or mesh or group or submesh - # @param method flags passing splitting method: - # 1 - split the hexahedron into 5 tetrahedrons - # 2 - split the hexahedron into 6 tetrahedrons + # @param method flags passing splitting method: Hex_5Tet, Hex_6Tet, Hex_24Tet + # Hex_5Tet - split the hexahedron into 5 tetrahedrons, etc # @ingroup l2_modif_cutquadr - def SplitVolumesIntoTetra(self, elemIDs, method=1 ): + def SplitVolumesIntoTetra(self, elemIDs, method=Hex_5Tet ): if isinstance( elemIDs, Mesh ): elemIDs = elemIDs.GetMesh() + if ( isinstance( elemIDs, list )): + elemIDs = self.editor.MakeIDSource(elemIDs, SMESH.VOLUME) self.editor.SplitVolumesIntoTetra(elemIDs, method) ## Splits quadrangle faces near triangular facets of volumes @@ -2727,6 +3013,9 @@ class Mesh: ## Converts the mesh to quadratic, deletes old elements, replacing # them with quadratic with the same id. + # @param theForce3d new node creation method: + # 0 - the medium node lies at the geometrical edge from which the mesh element is built + # 1 - the medium node lies at the middle of the line segments connecting start and end node of a mesh element # @ingroup l2_modif_tofromqu def ConvertToQuadratic(self, theForce3d): self.editor.ConvertToQuadratic(theForce3d) @@ -2744,7 +3033,34 @@ class Mesh: # @ingroup l2_modif_edit def Make2DMeshFrom3D(self): return self.editor. Make2DMeshFrom3D() - + + ## Creates missing boundary elements + # @param elements - elements whose boundary is to be checked: + # mesh, group, sub-mesh or list of elements + # @param dimension - defines type of boundary elements to create: + # SMESH.BND_2DFROM3D, SMESH.BND_1DFROM3D, SMESH.BND_1DFROM2D + # @param groupName - a name of group to store created boundary elements in, + # "" means not to create the group + # @param meshName - a name of new mesh to store created boundary elements in, + # "" means not to create the new mesh + # @param toCopyElements - if true, the checked elements will be copied into the new mesh + # @param toCopyExistingBondary - if true, not only new but also pre-existing + # boundary elements will be copied into the new mesh + # @return tuple (mesh, group) where bondary elements were added to + # @ingroup l2_modif_edit + def MakeBoundaryMesh(self, elements, dimension=SMESH.BND_2DFROM3D, groupName="", meshName="", + toCopyElements=False, toCopyExistingBondary=False): + if isinstance( elements, Mesh ): + elements = elements.GetMesh() + if ( isinstance( elements, list )): + elemType = SMESH.ALL + if elements: elemType = self.GetElementType( elements[0], iselem=True) + elements = self.editor.MakeIDSource(elements, elemType) + mesh, group = self.editor.MakeBoundaryMesh(elements,dimension,groupName,meshName, + toCopyElements,toCopyExistingBondary) + if mesh: mesh = self.smeshpyD.Mesh(mesh) + return mesh, group + ## Renumber mesh nodes # @ingroup l2_modif_renumber def RenumberNodes(self): @@ -3374,7 +3690,7 @@ class Mesh: ## Scales the object # @param theObject - the object to translate (mesh, submesh, or group) # @param thePoint - base point for scale - # @param theScaleFact - scale factors for axises + # @param theScaleFact - list of 1-3 scale factors for axises # @param Copy - allows copying the translated elements # @param MakeGroups - forces the generation of new groups from existing # ones (if Copy) @@ -3384,7 +3700,7 @@ class Mesh: if ( isinstance( theObject, Mesh )): theObject = theObject.GetMesh() if ( isinstance( theObject, list )): - theObject = self.editor.MakeIDSource(theObject) + theObject = self.editor.MakeIDSource(theObject, SMESH.ALL) thePoint, Parameters = ParsePointStruct(thePoint) self.mesh.SetParameters(Parameters) @@ -3397,7 +3713,7 @@ class Mesh: ## Creates a new mesh from the translated object # @param theObject - the object to translate (mesh, submesh, or group) # @param thePoint - base point for scale - # @param theScaleFact - scale factors for axises + # @param theScaleFact - list of 1-3 scale factors for axises # @param MakeGroups - forces the generation of new groups from existing ones # @param NewMeshName - the name of the newly created mesh # @return instance of Mesh class @@ -3405,7 +3721,7 @@ class Mesh: if (isinstance(theObject, Mesh)): theObject = theObject.GetMesh() if ( isinstance( theObject, list )): - theObject = self.editor.MakeIDSource(theObject) + theObject = self.editor.MakeIDSource(theObject,SMESH.ALL) mesh = self.editor.ScaleMakeMesh(theObject, thePoint, theScaleFact, MakeGroups, NewMeshName) @@ -3530,10 +3846,17 @@ class Mesh: ## Finds groups of ajacent nodes within Tolerance. # @param Tolerance the value of tolerance # @param SubMeshOrGroup SubMesh or Group + # @param exceptNodes list of either SubMeshes, Groups or node IDs to exclude from search # @return the list of groups of nodes # @ingroup l2_modif_trsf - def FindCoincidentNodesOnPart (self, SubMeshOrGroup, Tolerance): - return self.editor.FindCoincidentNodesOnPart(SubMeshOrGroup, Tolerance) + def FindCoincidentNodesOnPart (self, SubMeshOrGroup, Tolerance, exceptNodes=[]): + if (isinstance( SubMeshOrGroup, Mesh )): + SubMeshOrGroup = SubMeshOrGroup.GetMesh() + if not isinstance( exceptNodes, list): + exceptNodes = [ exceptNodes ] + if exceptNodes and isinstance( exceptNodes[0], int): + exceptNodes = [ self.editor.MakeIDSource( exceptNodes, SMESH.NODE)] + return self.editor.FindCoincidentNodesOnPartBut(SubMeshOrGroup, Tolerance,exceptNodes) ## Merges nodes # @param GroupsOfNodes the list of groups of nodes @@ -3649,11 +3972,15 @@ class Mesh: # This method provided for convenience works as DoubleNodes() described above. # @param theNodes group of nodes to be doubled # @param theModifiedElems group of elements to be updated. - # @return TRUE if operation has been completed successfully, FALSE otherwise + # @param theMakeGroup forces the generation of a group containing new nodes. + # @return TRUE or a created group if operation has been completed successfully, + # FALSE or None otherwise # @ingroup l2_modif_edit - def DoubleNodeGroup(self, theNodes, theModifiedElems): + def DoubleNodeGroup(self, theNodes, theModifiedElems, theMakeGroup=False): + if theMakeGroup: + return self.editor.DoubleNodeGroupNew(theNodes, theModifiedElems) return self.editor.DoubleNodeGroup(theNodes, theModifiedElems) - + ## Creates a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. # @param theNodes list of groups of nodes to be doubled @@ -3692,10 +4019,13 @@ class Mesh: # @param theNodesNot - group of nodes not to replicated # @param theAffectedElems - group of elements to which the replicated nodes # should be associated to. + # @param theMakeGroup forces the generation of a group containing new elements. # @ingroup l2_modif_edit - def DoubleNodeElemGroup(self, theElems, theNodesNot, theAffectedElems): + def DoubleNodeElemGroup(self, theElems, theNodesNot, theAffectedElems, theMakeGroup=False): + if theMakeGroup: + return self.editor.DoubleNodeElemGroupNew(theElems, theNodesNot, theAffectedElems) return self.editor.DoubleNodeElemGroup(theElems, theNodesNot, theAffectedElems) - + ## Creates a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. # @param theElems - group of of elements (edges or faces) to be replicated @@ -3730,6 +4060,86 @@ class Mesh: def DoubleNodeElemGroupsInRegion(self, theElems, theNodesNot, theShape): return self.editor.DoubleNodeElemGroupsInRegion(theElems, theNodesNot, theShape) + def _valueFromFunctor(self, funcType, elemId): + fn = self.smeshpyD.GetFunctor(funcType) + fn.SetMesh(self.mesh) + if fn.GetElementType() == self.GetElementType(elemId, True): + val = fn.GetValue(elemId) + else: + val = 0 + return val + + ## Get length of 1D element. + # @param elemId mesh element ID + # @return element's length value + # @ingroup l1_measurements + def GetLength(self, elemId): + return self._valueFromFunctor(SMESH.FT_Length, elemId) + + ## Get area of 2D element. + # @param elemId mesh element ID + # @return element's area value + # @ingroup l1_measurements + def GetArea(self, elemId): + return self._valueFromFunctor(SMESH.FT_Area, elemId) + + ## Get volume of 3D element. + # @param elemId mesh element ID + # @return element's volume value + # @ingroup l1_measurements + def GetVolume(self, elemId): + return self._valueFromFunctor(SMESH.FT_Volume3D, elemId) + + ## Get maximum element length. + # @param elemId mesh element ID + # @return element's maximum length value + # @ingroup l1_measurements + def GetMaxElementLength(self, elemId): + if self.GetElementType(elemId, True) == SMESH.VOLUME: + ftype = SMESH.FT_MaxElementLength3D + else: + ftype = SMESH.FT_MaxElementLength2D + return self._valueFromFunctor(ftype, elemId) + + ## Get aspect ratio of 2D or 3D element. + # @param elemId mesh element ID + # @return element's aspect ratio value + # @ingroup l1_measurements + def GetAspectRatio(self, elemId): + if self.GetElementType(elemId, True) == SMESH.VOLUME: + ftype = SMESH.FT_AspectRatio3D + else: + ftype = SMESH.FT_AspectRatio + return self._valueFromFunctor(ftype, elemId) + + ## Get warping angle of 2D element. + # @param elemId mesh element ID + # @return element's warping angle value + # @ingroup l1_measurements + def GetWarping(self, elemId): + return self._valueFromFunctor(SMESH.FT_Warping, elemId) + + ## Get minimum angle of 2D element. + # @param elemId mesh element ID + # @return element's minimum angle value + # @ingroup l1_measurements + def GetMinimumAngle(self, elemId): + return self._valueFromFunctor(SMESH.FT_MinimumAngle, elemId) + + ## Get taper of 2D element. + # @param elemId mesh element ID + # @return element's taper value + # @ingroup l1_measurements + def GetTaper(self, elemId): + return self._valueFromFunctor(SMESH.FT_Taper, elemId) + + ## Get skew of 2D element. + # @param elemId mesh element ID + # @return element's skew value + # @ingroup l1_measurements + def GetSkew(self, elemId): + return self._valueFromFunctor(SMESH.FT_Skew, elemId) + ## The mother class to define algorithm, it is not recommended to use it directly. # # More details. @@ -3882,7 +4292,8 @@ class Mesh_Algorithm: pass except: name = mesh.geompyD.SubShapeName(geom, piece) - mesh.geompyD.addToStudyInFather(piece, geom, name) + if not name: + name = "%s_%s"%(geom.GetShapeType(), id(geom%1000)) pass self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName()) @@ -4015,6 +4426,8 @@ class Mesh_Segment(Mesh_Algorithm): if not isinstance(reversedEdges,list): #old version script, before adding reversedEdges reversedEdges, UseExisting = [], reversedEdges entry = self.MainShapeEntry() + if reversedEdges and isinstance(reversedEdges[0],geompyDC.GEOM._objref_GEOM_Object): + reversedEdges = [ self.mesh.geompyD.GetSubShapeID(self.mesh.geom, e) for e in reversedEdges ] if s == []: hyp = self.Hypothesis("NumberOfSegments", [n, reversedEdges, entry], UseExisting=UseExisting, @@ -4057,6 +4470,8 @@ class Mesh_Segment(Mesh_Algorithm): def Arithmetic1D(self, start, end, reversedEdges=[], UseExisting=0): if not isinstance(reversedEdges,list): #old version script, before adding reversedEdges reversedEdges, UseExisting = [], reversedEdges + if reversedEdges and isinstance(reversedEdges[0],geompyDC.GEOM._objref_GEOM_Object): + reversedEdges = [ self.mesh.geompyD.GetSubShapeID(self.mesh.geom, e) for e in reversedEdges ] entry = self.MainShapeEntry() hyp = self.Hypothesis("Arithmetic1D", [start, end, reversedEdges, entry], UseExisting=UseExisting, @@ -4093,9 +4508,8 @@ class Mesh_Segment(Mesh_Algorithm): def FixedPoints1D(self, points, nbSegs=[1], reversedEdges=[], UseExisting=0): if not isinstance(reversedEdges,list): #old version script, before adding reversedEdges reversedEdges, UseExisting = [], reversedEdges - if reversedEdges and isinstance( reversedEdges[0], geompyDC.GEOM._objref_GEOM_Object ): - for i in range( len( reversedEdges )): - reversedEdges[i] = self.mesh.geompyD.GetSubShapeID(self.mesh.geom, reversedEdges[i] ) + if reversedEdges and isinstance(reversedEdges[0],geompyDC.GEOM._objref_GEOM_Object): + reversedEdges = [ self.mesh.geompyD.GetSubShapeID(self.mesh.geom, e) for e in reversedEdges ] entry = self.MainShapeEntry() hyp = self.Hypothesis("FixedPoints1D", [points, nbSegs, reversedEdges, entry], UseExisting=UseExisting, @@ -4130,6 +4544,8 @@ class Mesh_Segment(Mesh_Algorithm): def StartEndLength(self, start, end, reversedEdges=[], UseExisting=0): if not isinstance(reversedEdges,list): #old version script, before adding reversedEdges reversedEdges, UseExisting = [], reversedEdges + if reversedEdges and isinstance(reversedEdges[0],geompyDC.GEOM._objref_GEOM_Object): + reversedEdges = [ self.mesh.geompyD.GetSubShapeID(self.mesh.geom, e) for e in reversedEdges ] entry = self.MainShapeEntry() hyp = self.Hypothesis("StartEndLength", [start, end, reversedEdges, entry], UseExisting=UseExisting, @@ -4389,7 +4805,7 @@ class Mesh_Triangle(Mesh_Algorithm): self.Parameters().SetPhyMax(theVal) ## Sets a way to define maximum angular deflection of mesh from CAD model. - # @param theGeometricMesh is: DefaultGeom or Custom + # @param theGeometricMesh is: 0 (None) or 1 (Custom) # @ingroup l3_hypos_blsurf def SetGeometricMesh(self, theGeometricMesh=0): # Parameter of BLSURF algo @@ -4587,48 +5003,96 @@ class Mesh_Triangle(Mesh_Algorithm): # @ingroup l3_algos_basic class Mesh_Quadrangle(Mesh_Algorithm): + params=0 + ## Private constructor. def __init__(self, mesh, geom=0): Mesh_Algorithm.__init__(self) self.Create(mesh, geom, "Quadrangle_2D") + return - ## Defines "QuadranglePreference" hypothesis, forcing construction - # of quadrangles if the number of nodes on the opposite edges is not the same - # while the total number of nodes on edges is even - # - # @ingroup l3_hypos_additi - def QuadranglePreference(self): - hyp = self.Hypothesis("QuadranglePreference", UseExisting=1, - CompareMethod=self.CompareEqualHyp) - return hyp + ## Defines "QuadrangleParameters" hypothesis + # @param quadType defines the algorithm of transition between differently descretized + # sides of a geometrical face: + # - QUAD_STANDARD - both triangles and quadrangles are possible in the transition + # area along the finer meshed sides. + # - QUAD_TRIANGLE_PREF - only triangles are built in the transition area along the + # finer meshed sides. + # - QUAD_QUADRANGLE_PREF - only quadrangles are built in the transition area along + # the finer meshed sides, iff the total quantity of segments on + # all four sides of the face is even (divisible by 2). + # - QUAD_QUADRANGLE_PREF_REVERSED - same as QUAD_QUADRANGLE_PREF but the transition + # area is located along the coarser meshed sides. + # - QUAD_REDUCED - only quadrangles are built and the transition between the sides + # is made gradually, layer by layer. This type has a limitation on + # the number of segments: one pair of opposite sides must have the + # same number of segments, the other pair must have an even difference + # between the numbers of segments on the sides. + # @param triangleVertex: vertex of a trilateral geometrical face, around which triangles + # will be created while other elements will be quadrangles. + # Vertex can be either a GEOM_Object or a vertex ID within the + # shape to mesh + # @param UseExisting: if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + # @ingroup l3_hypos_quad + def QuadrangleParameters(self, quadType=StdMeshers.QUAD_STANDARD, triangleVertex=0, UseExisting=0): + vertexID = triangleVertex + if isinstance( triangleVertex, geompyDC.GEOM._objref_GEOM_Object ): + vertexID = self.mesh.geompyD.GetSubShapeID( self.mesh.geom, triangleVertex ) + if not self.params: + compFun = lambda hyp,args: \ + hyp.GetQuadType() == args[0] and \ + ( hyp.GetTriaVertex()==args[1] or ( hyp.GetTriaVertex()<1 and args[1]<1)) + self.params = self.Hypothesis("QuadrangleParams", [quadType,vertexID], + UseExisting = UseExisting, CompareMethod=compFun) + pass + if self.params.GetQuadType() != quadType: + self.params.SetQuadType(quadType) + if vertexID > 0: + self.params.SetTriaVertex( vertexID ) + return self.params - ## Defines "TrianglePreference" hypothesis, forcing construction - # of triangles in the refinement area if the number of nodes - # on the opposite edges is not the same - # - # @ingroup l3_hypos_additi - def TrianglePreference(self): - hyp = self.Hypothesis("TrianglePreference", UseExisting=1, - CompareMethod=self.CompareEqualHyp) - return hyp + ## Defines "QuadrangleParams" hypothesis with a type of quadrangulation that only + # quadrangles are built in the transition area along the finer meshed sides, + # iff the total quantity of segments on all four sides of the face is even. + # @param reversed if True, transition area is located along the coarser meshed sides. + # @param UseExisting: if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + # @ingroup l3_hypos_quad + def QuadranglePreference(self, reversed=False, UseExisting=0): + if reversed: + return self.QuadrangleParameters(QUAD_QUADRANGLE_PREF_REVERSED,UseExisting=UseExisting) + return self.QuadrangleParameters(QUAD_QUADRANGLE_PREF,UseExisting=UseExisting) + + ## Defines "QuadrangleParams" hypothesis with a type of quadrangulation that only + # triangles are built in the transition area along the finer meshed sides. + # @param UseExisting: if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + # @ingroup l3_hypos_quad + def TrianglePreference(self, UseExisting=0): + return self.QuadrangleParameters(QUAD_TRIANGLE_PREF,UseExisting=UseExisting) + + ## Defines "QuadrangleParams" hypothesis with a type of quadrangulation that only + # quadrangles are built and the transition between the sides is made gradually, + # layer by layer. This type has a limitation on the number of segments: one pair + # of opposite sides must have the same number of segments, the other pair must + # have an even difference between the numbers of segments on the sides. + # @param UseExisting: if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + # @ingroup l3_hypos_quad + def Reduced(self, UseExisting=0): + return self.QuadrangleParameters(QUAD_REDUCED,UseExisting=UseExisting) - ## Defines "QuadrangleParams" hypothesis + ## Defines "QuadrangleParams" hypothesis with QUAD_STANDARD type of quadrangulation # @param vertex: vertex of a trilateral geometrical face, around which triangles # will be created while other elements will be quadrangles. # Vertex can be either a GEOM_Object or a vertex ID within the # shape to mesh # @param UseExisting: if ==true - searches for the existing hypothesis created with # the same parameters, else (default) - creates a new one - # - # @ingroup l3_hypos_additi + # @ingroup l3_hypos_quad def TriangleVertex(self, vertex, UseExisting=0): - vertexID = vertex - if isinstance( vertexID, geompyDC.GEOM._objref_GEOM_Object ): - vertexID = self.mesh.geompyD.GetSubShapeID( self.mesh.geom, vertex ) - hyp = self.Hypothesis("QuadrangleParams", [vertexID], UseExisting = UseExisting, - CompareMethod=lambda hyp,args: hyp.GetTriaVertex()==args[0]) - hyp.SetTriaVertex( vertexID ) - return hyp + return self.QuadrangleParameters(QUAD_STANDARD,vertex,UseExisting) # Public class: Mesh_Tetrahedron @@ -5305,6 +5769,73 @@ class Mesh_RadialQuadrangle1D2D(Mesh_Algorithm): return hyp +# Public class: Mesh_UseExistingElements +# -------------------------------------- +## Defines a Radial Quadrangle 1D2D algorithm +# @ingroup l3_algos_basic +# +class Mesh_UseExistingElements(Mesh_Algorithm): + + def __init__(self, dim, mesh, geom=0): + if dim == 1: + self.Create(mesh, geom, "Import_1D") + else: + self.Create(mesh, geom, "Import_1D2D") + return + + ## Defines "Source edges" hypothesis, specifying groups of edges to import + # @param groups list of groups of edges + # @param toCopyMesh if True, the whole mesh \a groups belong to is imported + # @param toCopyGroups if True, all groups of the mesh \a groups belong to are imported + # @param UseExisting if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + def SourceEdges(self, groups, toCopyMesh=False, toCopyGroups=False, UseExisting=False): + if self.algo.GetName() == "Import_2D": + raise ValueError, "algoritm dimension mismatch" + hyp = self.Hypothesis("ImportSource1D", [groups, toCopyMesh, toCopyGroups], + UseExisting=UseExisting, CompareMethod=self._compareHyp) + hyp.SetSourceEdges(groups) + hyp.SetCopySourceMesh(toCopyMesh, toCopyGroups) + return hyp + + ## Defines "Source faces" hypothesis, specifying groups of faces to import + # @param groups list of groups of faces + # @param toCopyMesh if True, the whole mesh \a groups belong to is imported + # @param toCopyGroups if True, all groups of the mesh \a groups belong to are imported + # @param UseExisting if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + def SourceFaces(self, groups, toCopyMesh=False, toCopyGroups=False, UseExisting=False): + if self.algo.GetName() == "Import_1D": + raise ValueError, "algoritm dimension mismatch" + hyp = self.Hypothesis("ImportSource2D", [groups, toCopyMesh, toCopyGroups], + UseExisting=UseExisting, CompareMethod=self._compareHyp) + hyp.SetSourceFaces(groups) + hyp.SetCopySourceMesh(toCopyMesh, toCopyGroups) + return hyp + + def _compareHyp(self,hyp,args): + if hasattr( hyp, "GetSourceEdges"): + entries = hyp.GetSourceEdges() + else: + entries = hyp.GetSourceFaces() + groups = args[0] + toCopyMesh,toCopyGroups = hyp.GetCopySourceMesh() + if len(entries)==len(groups) and toCopyMesh==args[1] and toCopyGroups==args[2]: + entries2 = [] + study = self.mesh.smeshpyD.GetCurrentStudy() + if study: + for g in groups: + ior = salome.orb.object_to_string(g) + sobj = study.FindObjectIOR(ior) + if sobj: entries2.append( sobj.GetID() ) + pass + pass + entries.sort() + entries2.sort() + return entries == entries2 + return False + + # Private class: Mesh_UseExisting # ------------------------------- class Mesh_UseExisting(Mesh_Algorithm): diff --git a/src/StdMeshers/Makefile.am b/src/StdMeshers/Makefile.am index 0312e1f78..08c312ead 100644 --- a/src/StdMeshers/Makefile.am +++ b/src/StdMeshers/Makefile.am @@ -72,7 +72,10 @@ salomeinclude_HEADERS = \ StdMeshers_MaxLength.hxx \ StdMeshers_QuadrangleParams.hxx \ StdMeshers_RadialQuadrangle_1D2D.hxx \ - StdMeshers_HexaFromSkin_3D.hxx + StdMeshers_HexaFromSkin_3D.hxx \ + StdMeshers_ImportSource.hxx \ + StdMeshers_Import_1D.hxx \ + StdMeshers_Import_1D2D.hxx # Libraries targets @@ -123,7 +126,10 @@ dist_libStdMeshers_la_SOURCES = \ StdMeshers_MaxLength.cxx \ StdMeshers_QuadrangleParams.cxx \ StdMeshers_RadialQuadrangle_1D2D.cxx \ - StdMeshers_HexaFromSkin_3D.cxx + StdMeshers_HexaFromSkin_3D.cxx \ + StdMeshers_ImportSource.cxx \ + StdMeshers_Import_1D.cxx \ + StdMeshers_Import_1D2D.cxx # additionnal information to compil and link file diff --git a/src/StdMeshers/StdMeshers_CompositeSegment_1D.hxx b/src/StdMeshers/StdMeshers_CompositeSegment_1D.hxx index 7f003f4ae..4812b4235 100644 --- a/src/StdMeshers/StdMeshers_CompositeSegment_1D.hxx +++ b/src/StdMeshers/StdMeshers_CompositeSegment_1D.hxx @@ -23,7 +23,6 @@ // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_CompositeSegment_1D.hxx // Module : SMESH -// $Header$ // #ifndef _SMESH_CompositeSegment_1D_HXX_ #define _SMESH_CompositeSegment_1D_HXX_ diff --git a/src/StdMeshers/StdMeshers_FaceSide.cxx b/src/StdMeshers/StdMeshers_FaceSide.cxx index 036da0ba9..f882f5c92 100644 --- a/src/StdMeshers/StdMeshers_FaceSide.cxx +++ b/src/StdMeshers/StdMeshers_FaceSide.cxx @@ -452,9 +452,12 @@ void StdMeshers_FaceSide::Reverse() reverse( myEdgeLength ); reverse( myIsUniform ); } - myNormPar[nbEdges-1]=1.; - myPoints.clear(); - myFalsePoints.clear(); + if ( nbEdges > 0 ) + { + myNormPar[nbEdges-1]=1.; + myPoints.clear(); + myFalsePoints.clear(); + } } //================================================================================ diff --git a/src/StdMeshers/StdMeshers_HexaFromSkin_3D.cxx b/src/StdMeshers/StdMeshers_HexaFromSkin_3D.cxx index 6e8448e0a..e7409c108 100644 --- a/src/StdMeshers/StdMeshers_HexaFromSkin_3D.cxx +++ b/src/StdMeshers/StdMeshers_HexaFromSkin_3D.cxx @@ -31,6 +31,7 @@ #include //#include "utilities.h" +#include // Define error message #ifdef _DEBUG_ @@ -53,10 +54,12 @@ namespace { B_BOTTOM=0, B_RIGHT, B_TOP, B_LEFT, B_FRONT, B_BACK, NB_BLOCK_SIDES }; +#ifdef _DEBUG_ // avoid unused variables in release mode const char* SBoxSides[] = //!< names of block sides { "BOTTOM", "RIGHT", "TOP", "LEFT", "FRONT", "BACK", "UNDEFINED" }; +#endif enum EQuadEdge //!< edges of quadrangle side { Q_BOTTOM = 0, Q_RIGHT, Q_TOP, Q_LEFT, NB_QUAD_SIDES @@ -1080,18 +1083,49 @@ bool StdMeshers_HexaFromSkin_3D::Compute(SMESH_Mesh & aMesh, SMESH_MesherHelper* // Add hexahedrons // ---------------- - // find out orientation - const SMDS_MeshNode* n000 = block.getSide(B_BOTTOM).cornerNode( 0, 0 ); - const SMDS_MeshNode* n100 = block.getSide(B_BOTTOM).cornerNode( 1, 0 ); - const SMDS_MeshNode* n010 = block.getSide(B_BOTTOM).cornerNode( 0, 1 ); - const SMDS_MeshNode* n110 = block.getSide(B_BOTTOM).cornerNode( 1, 1 ); - const SMDS_MeshNode* n001 = block.getSide(B_TOP).cornerNode( 0, 0 ); - const SMDS_MeshNode* n101 = block.getSide(B_TOP).cornerNode( 1, 0 ); - const SMDS_MeshNode* n011 = block.getSide(B_TOP).cornerNode( 0, 1 ); - const SMDS_MeshNode* n111 = block.getSide(B_TOP).cornerNode( 1, 1 ); - SMDS_VolumeOfNodes probeVolume (n000,n010,n110,n100, - n001,n011,n111,n101); - bool isForw = SMDS_VolumeTool( &probeVolume ).IsForward(); + // find out orientation by a least distorted hexahedron (issue 0020855); + // the last is defined by evaluating sum of face normals of 8 corner hexahedrons + double badness = numeric_limits::max(); + bool isForw = true; + for ( int xMax = 0; xMax < 2; ++xMax ) + for ( int yMax = 0; yMax < 2; ++yMax ) + for ( int zMax = 0; zMax < 2; ++zMax ) + { + x = xMax ? xSize-1 : 1; + y = yMax ? ySize-1 : 1; + z = zMax ? zSize-1 : 1; + vector< const SMDS_MeshNode* >& col00 = columns[ colIndex( x-1, y-1 )]; + vector< const SMDS_MeshNode* >& col10 = columns[ colIndex( x , y-1 )]; + vector< const SMDS_MeshNode* >& col01 = columns[ colIndex( x-1, y )]; + vector< const SMDS_MeshNode* >& col11 = columns[ colIndex( x , y )]; + + const SMDS_MeshNode* n000 = col00[z-1]; + const SMDS_MeshNode* n100 = col10[z-1]; + const SMDS_MeshNode* n010 = col01[z-1]; + const SMDS_MeshNode* n110 = col11[z-1]; + const SMDS_MeshNode* n001 = col00[z]; + const SMDS_MeshNode* n101 = col10[z]; + const SMDS_MeshNode* n011 = col01[z]; + const SMDS_MeshNode* n111 = col11[z]; + SMDS_VolumeOfNodes probeVolume (n000,n010,n110,n100, + n001,n011,n111,n101); + SMDS_VolumeTool volTool( &probeVolume ); + double Nx=0.,Ny=0.,Nz=0.; + for ( int iFace = 0; iFace < volTool.NbFaces(); ++iFace ) + { + double nx,ny,nz; + volTool.GetFaceNormal( iFace, nx,ny,nz ); + Nx += nx; + Ny += ny; + Nz += nz; + } + double quality = Nx*Nx + Ny*Ny + Nz*Nz; + if ( quality < badness ) + { + badness = quality; + isForw = volTool.IsForward(); + } + } // add elements for ( x = 0; x < xSize-1; ++x ) { diff --git a/src/StdMeshers/StdMeshers_ImportSource.cxx b/src/StdMeshers/StdMeshers_ImportSource.cxx new file mode 100644 index 000000000..1ba39eacf --- /dev/null +++ b/src/StdMeshers/StdMeshers_ImportSource.cxx @@ -0,0 +1,443 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH StdMeshers_ImportSource1D : implementaion of SMESH idl descriptions +// File : StdMeshers_ImportSource1D.cxx +// Module : SMESH +// +#include "StdMeshers_ImportSource.hxx" + +#include "SMESHDS_GroupBase.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_Algo.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Group.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_subMeshEventListener.hxx" + +#include "utilities.h" + +#include + +#include + +using namespace std; + +//============================================================================= +/*! + * Creates StdMeshers_ImportSource1D + */ +//============================================================================= + +StdMeshers_ImportSource1D::StdMeshers_ImportSource1D(int hypId, + int studyId, + SMESH_Gen * gen) + :SMESH_Hypothesis(hypId, studyId, gen), + _toCopyMesh(false), + _toCopyGroups(false) +{ + _name = "ImportSource1D"; + _param_algo_dim = 1; // is used by StdMeshers_Import_1D; +} + +//============================================================================= +/*! + * Creates StdMeshers_ImportSource2D + */ +//============================================================================= + +StdMeshers_ImportSource2D::StdMeshers_ImportSource2D(int hypId, + int studyId, + SMESH_Gen * gen) + :StdMeshers_ImportSource1D(hypId, studyId, gen) +{ + _name = "ImportSource2D"; + _param_algo_dim = 2; // is used by StdMeshers_Import_2D; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +StdMeshers_ImportSource1D::~StdMeshers_ImportSource1D() +{ +} +//============================================================================= +/*! + * Sets groups to import elements from + */ +//============================================================================= + +void StdMeshers_ImportSource1D::SetGroups(const std::vector& groups) +{ + if (_groups != groups) + { + _groups = groups; + NotifySubMeshesHypothesisModification(); + } +} + +void StdMeshers_ImportSource1D::SetCopySourceMesh(bool toCopyMesh, bool toCopyGroups) +{ + if ( !toCopyMesh ) toCopyGroups = false; + if ( _toCopyMesh != toCopyMesh || _toCopyGroups != toCopyGroups ) + { + _toCopyMesh = toCopyMesh; _toCopyGroups = toCopyGroups; + NotifySubMeshesHypothesisModification(); + } +} +void StdMeshers_ImportSource1D::GetCopySourceMesh(bool& toCopyMesh, bool& toCopyGroups) const +{ + toCopyMesh = _toCopyMesh; toCopyGroups = _toCopyGroups; +} + +namespace +{ + //================================================================================ + /*! + * \brief Return only alive groups + */ + //================================================================================ + + vector getValidGroups(const vector& groups, + StudyContextStruct* studyContext) + { + vector okGroups; + for ( int i = 0; i < groups.size(); ++i ) + { + try + { + // we expect SIGSEGV on a dead group + OCC_CATCH_SIGNALS; + SMESH_Group* okGroup = 0; + map::iterator itm = itm = studyContext->mapMesh.begin(); + for ( ; !okGroup && itm != studyContext->mapMesh.end(); itm++) + { + SMESH_Mesh::GroupIteratorPtr gIt = itm->second->GetGroups(); + while ( gIt->more() && !okGroup ) + if ( gIt->next() == groups[i] ) + okGroup = groups[i]; + } + if ( okGroup ) + okGroups.push_back( okGroup ); + } + catch(...) + { + } + } + return okGroups; + } + //================================================================================ + /*! + * \brief Pack meshes into a pair of ints + */ + //================================================================================ + + pair getResMapKey(const SMESHDS_Mesh& srcMesh, const SMESHDS_Mesh& tgtMesh) + { + return make_pair( srcMesh.GetPersistentId() , tgtMesh.GetPersistentId() ); + } + //================================================================================ + /*! + * \brief Return a target mesh by a pair of ints + */ + //================================================================================ + + SMESH_Mesh* getTgtMeshByKey( const pair & resMapKey, + StudyContextStruct* studyContext) + { + int tgtID = resMapKey.second; + SMESH_Mesh* tgtMesh = 0; + map::iterator itm = itm = studyContext->mapMesh.begin(); + for ( ; !tgtMesh && itm != studyContext->mapMesh.end(); itm++) + { + tgtMesh = (*itm).second; + if ( tgtMesh->GetMeshDS()->GetPersistentId() != tgtID ) + tgtMesh = 0; + } + return tgtMesh; + } + //================================================================================ + /*! + * \brief Return a target mesh by a pair of ints + */ + //================================================================================ + + int getSrcMeshID( const pair & resMapKey ) + { + return resMapKey.first; + } +} + +//============================================================================= +/*! + * Returns groups to import elements from + */ +//============================================================================= + +const std::vector& StdMeshers_ImportSource1D::GetGroups() const +{ + // filter off deleted groups + vector okGroups = getValidGroups( _groups, + _gen->GetStudyContext(_studyId) ); + if ( okGroups.size() != _groups.size() ) + ((StdMeshers_ImportSource1D*)this)->_groups = okGroups; + + return _groups; +} + +//================================================================================ +/*! + * \brief Return source meshes + */ +//================================================================================ + +std::vector StdMeshers_ImportSource1D::GetSourceMeshes() const +{ + // GetPersistentId()'s of meshes + set meshIDs; + const vector& groups = GetGroups(); + if ( !groups.empty() ) + { + for ( unsigned i = 0; i < groups.size(); ++i ) + { + const SMESHDS_GroupBase* gDS = groups[i]->GetGroupDS(); + int id = gDS->GetMesh()->GetPersistentId(); + meshIDs.insert( id ); + } + } + else + { + if ( _resultGroups.empty() ) + ((StdMeshers_ImportSource1D*)this)->RestoreGroups(_groups); + TResGroupMap::const_iterator key_groups = _resultGroups.begin(); + for ( ; key_groups != _resultGroups.end(); ++key_groups ) + meshIDs.insert( getSrcMeshID( key_groups->first )); + } + + // Find corresponding meshes + vector meshes; + if ( !meshIDs.empty() ) + { + StudyContextStruct* studyContext = _gen->GetStudyContext(_studyId); + for ( set::iterator id = meshIDs.begin(); id != meshIDs.end(); ++id ) + { + map::iterator itm = itm = studyContext->mapMesh.begin(); + for ( ; itm != studyContext->mapMesh.end(); itm++) + { + SMESH_Mesh* mesh = (*itm).second; + if ( mesh->GetMeshDS()->GetPersistentId() == *id ) + { + meshes.push_back( mesh ); + break; + } + } + } + } + return meshes; +} + +//============================================================================= +/*! + * Save _toCopyMesh and _toCopyGroups to a stream + */ +//============================================================================= + +ostream & StdMeshers_ImportSource1D::SaveTo(ostream & save) +{ + resultGroupsToIntVec(); + + save << " " << _toCopyMesh << " " << _toCopyGroups; + save << " " << _resultGroupsStorage.size(); + for ( unsigned i = 0; i < _resultGroupsStorage.size(); ++i ) + save << " " << _resultGroupsStorage[i]; + + return save; +} + +//============================================================================= +/*! + * Load _toCopyMesh and _toCopyGroups from a stream + */ +//============================================================================= + +istream & StdMeshers_ImportSource1D::LoadFrom(istream & load) +{ + load >> _toCopyMesh >> _toCopyGroups; + + _resultGroupsStorage.clear(); + int val; + if ( load >> val ) + { + _resultGroupsStorage.reserve(val); + while ( _resultGroupsStorage.size() < _resultGroupsStorage.capacity() && load >> val ) + _resultGroupsStorage.push_back( val ); + } + return load; +} + +//================================================================================ +/*! + * \brief Convert result groups into _resultGroupsStorage + */ +//================================================================================ + +void StdMeshers_ImportSource1D::resultGroupsToIntVec() +{ + _resultGroupsStorage.clear(); + + // store result groups + TResGroupMap::iterator key2groups = _resultGroups.begin(); + for ( ; key2groups != _resultGroups.end(); ++key2groups ) + { + const pair& key = key2groups->first; + const vector& groups = key2groups->second; + // mesh ids, nb groups + _resultGroupsStorage.push_back( key.first ); + _resultGroupsStorage.push_back( key.second ); + _resultGroupsStorage.push_back( groups.size() ); + for ( unsigned i = 0; i < groups.size(); ++i ) + { + // store group names as sequence of ints each standing for a char + // of a name; that is to avoid pb with names containing white spaces + string name = groups[i]->GetGroupDS()->GetStoreName(); + _resultGroupsStorage.push_back( name.size() ); + for ( unsigned j = 0; j < name.size(); ++j ) + _resultGroupsStorage.push_back( name[j] ); + } + } +} + +//================================================================================ +/*! + * \brief Restore source groups and result groups by _resultGroupsStorage + */ +//================================================================================ + +void StdMeshers_ImportSource1D::RestoreGroups(const std::vector& groups) +{ + _groups = groups; + + _resultGroups.clear(); + int i = 0; + while ( i < _resultGroupsStorage.size() ) + { + int key1 = _resultGroupsStorage[i++]; + int key2 = _resultGroupsStorage[i++]; + pair resMapKey( key1, key2 ); + SMESH_Mesh* mesh = getTgtMeshByKey( resMapKey, _gen->GetStudyContext(_studyId)); + // restore mesh ids at least + _resultGroups.insert( make_pair (resMapKey,vector() )); + + int nbGroups = _resultGroupsStorage[i++]; + for ( int j = 0; j < nbGroups; ++j ) + { + string::size_type nameSize = _resultGroupsStorage[i++]; + string groupName(nameSize, '\0'); + for ( unsigned k = 0; k < nameSize; ++k ) + groupName[k] = (char) _resultGroupsStorage[i++]; + + // find a group by name + if ( mesh ) + { + SMESH_Group* group = 0; + SMESH_Mesh::GroupIteratorPtr gIt = mesh->GetGroups(); + while ( !group && gIt->more() ) + { + group = gIt->next(); + if ( !group->GetGroupDS() || groupName != group->GetGroupDS()->GetStoreName() ) + group = 0; + } + if ( group ) + _resultGroups[ resMapKey ].push_back( group ); + } + } + } +} + +//================================================================================ +/*! + * \brief Remember groups imported from other mesh + * \param groups - result groups + * \param srcMesh - source mesh + * \param tgtMesh - destination mesh + */ +//================================================================================ + +void StdMeshers_ImportSource1D::StoreResultGroups(const std::vector& groups, + const SMESHDS_Mesh& srcMesh, + const SMESHDS_Mesh& tgtMesh) +{ + _resultGroups[ getResMapKey(srcMesh,tgtMesh) ] = groups; +} + +//================================================================================ +/*! + * \brief Return groups imported from other mesh + * \param srcMesh - source mesh + * \param tgtMesh - destination mesh + * \retval const std::vector& - groups + */ +//================================================================================ + +std::vector* +StdMeshers_ImportSource1D::GetResultGroups(const SMESHDS_Mesh& srcMesh, + const SMESHDS_Mesh& tgtMesh) +{ + TResGroupMap::iterator key2groups = _resultGroups.find( getResMapKey(srcMesh,tgtMesh )); + if ( key2groups == _resultGroups.end() ) + return 0; + vector vec = getValidGroups((*key2groups).second, + _gen->GetStudyContext(_studyId) ); + if ( vec.size() != key2groups->second.size()) + key2groups->second = vec; + + return & key2groups->second; +} + +//================================================================================ +/*! + * \brief Initialize ImportSource value by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_ImportSource1D::SetParametersByMesh(const SMESH_Mesh*, const TopoDS_Shape&) +{ + return false; +} + +//================================================================================ +/*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_ImportSource1D::SetParametersByDefaults(const TDefaults&, const SMESH_Mesh* ) +{ + return false; +} diff --git a/src/StdMeshers/StdMeshers_ImportSource.hxx b/src/StdMeshers/StdMeshers_ImportSource.hxx new file mode 100644 index 000000000..13287cb2e --- /dev/null +++ b/src/StdMeshers/StdMeshers_ImportSource.hxx @@ -0,0 +1,97 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH StdMeshers : implementaion of SMESH idl descriptions +// File : StdMeshers_ImportSource1D.hxx +// Module : SMESH +// +#ifndef _StdMeshers_ImportSource_HXX_ +#define _StdMeshers_ImportSource_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_Hypothesis.hxx" +#include "Utils_SALOME_Exception.hxx" + +#include +#include + +class SMESH_Group; +class SMESHDS_Mesh; + +//============================================================================== +/*! + * \brief Stores groups to import elements from + */ +//============================================================================== + +class STDMESHERS_EXPORT StdMeshers_ImportSource1D : public SMESH_Hypothesis +{ + public: + StdMeshers_ImportSource1D(int hypId, int studyId, SMESH_Gen * gen); + virtual ~ StdMeshers_ImportSource1D(); + + void SetGroups(const std::vector& groups); + const std::vector& GetGroups() const; + + void SetCopySourceMesh(bool toCopyMesh, bool toCopyGroups); + void GetCopySourceMesh(bool& toCopyMesh, bool& toCopyGroups) const; + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0); + void RestoreGroups(const std::vector& groups); + + void StoreResultGroups(const std::vector& groups, + const SMESHDS_Mesh& srcMesh, + const SMESHDS_Mesh& tgtMesh); + std::vector* GetResultGroups(const SMESHDS_Mesh& srcMesh, + const SMESHDS_Mesh& tgtMesh); + + std::vector GetSourceMeshes() const; + +private: + + std::vector _groups; + bool _toCopyMesh, _toCopyGroups; + + // groups imported using this hypothesis + typedef std::map< std::pair, std::vector > TResGroupMap; + TResGroupMap _resultGroups; + std::vector _resultGroupsStorage; // persistent representation of _resultGroups + + void resultGroupsToIntVec(); +}; + +//============================================================================== +/*! + * \brief Redefines name and dimension of inherited StdMeshers_ImportSource1D + */ +//============================================================================== + +class STDMESHERS_EXPORT StdMeshers_ImportSource2D : public StdMeshers_ImportSource1D +{ + public: + StdMeshers_ImportSource2D(int hypId, int studyId, SMESH_Gen * gen); +}; +#endif diff --git a/src/StdMeshers/StdMeshers_Import_1D.cxx b/src/StdMeshers/StdMeshers_Import_1D.cxx new file mode 100644 index 000000000..fe0f05476 --- /dev/null +++ b/src/StdMeshers/StdMeshers_Import_1D.cxx @@ -0,0 +1,959 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// File : StdMeshers_Import_1D.cxx +// Module : SMESH +// +#include "StdMeshers_Import_1D.hxx" +#include "StdMeshers_ImportSource.hxx" + +#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMESHDS_Group.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_Comment.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Group.hxx" +#include "SMESH_HypoFilter.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" + +#include "Utils_SALOME_Exception.hxx" +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +//============================================================================= +/*! + * Creates StdMeshers_Import_1D + */ +//============================================================================= + +StdMeshers_Import_1D::StdMeshers_Import_1D(int hypId, int studyId, SMESH_Gen * gen) + :SMESH_1D_Algo(hypId, studyId, gen), _sourceHyp(0) +{ + MESSAGE("StdMeshers_Import_1D::StdMeshers_Import_1D"); + _name = "Import_1D"; + _shapeType = (1 << TopAbs_EDGE); + + _compatibleHypothesis.push_back("ImportSource1D"); +} + +//============================================================================= +/*! + * Check presence of a hypothesis + */ +//============================================================================= + +bool StdMeshers_Import_1D::CheckHypothesis + (SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus) +{ + _sourceHyp = 0; + + const list &hyps = GetUsedHypothesis(aMesh, aShape); + if ( hyps.size() == 0 ) + { + aStatus = SMESH_Hypothesis::HYP_MISSING; + return false; // can't work with no hypothesis + } + + if ( hyps.size() > 1 ) + { + aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST; + return false; + } + + const SMESHDS_Hypothesis *theHyp = hyps.front(); + + string hypName = theHyp->GetName(); + + if (hypName == _compatibleHypothesis.front()) + { + _sourceHyp = (StdMeshers_ImportSource1D *)theHyp; + aStatus = SMESH_Hypothesis::HYP_OK; + return true; + } + + aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + return true; +} + +//================================================================================ +namespace // INTERNAL STUFF +//================================================================================ +{ + int getSubmeshIDForCopiedMesh(const SMESHDS_Mesh* srcMeshDS, SMESH_Mesh* tgtMesh); + + enum _ListenerDataType + { + WAIT_HYP_MODIF=1, // data indicating awaiting for valid parameters of src hyp + SRC_HYP // data storing ImportSource hyp + }; + //================================================================================ + /*! + * \brief _ListenerData holding ImportSource hyp holding in its turn + * imported groups + */ + struct _ListenerData : public SMESH_subMeshEventListenerData + { + const StdMeshers_ImportSource1D* _srcHyp; + _ListenerData(const StdMeshers_ImportSource1D* h): + SMESH_subMeshEventListenerData(/*isDeletable=*/true), _srcHyp(h) + { + myType = SRC_HYP; + } + }; + //================================================================================ + /*! + * \brief Container of data dedicated to one source mesh + */ + struct _ImportData + { + const SMESH_Mesh* _srcMesh; + StdMeshers_Import_1D::TNodeNodeMap _n2n; + StdMeshers_Import_1D::TElemElemMap _e2e; + + set< SMESH_subMesh*> _subM; // submeshes relating to this srcMesh + set< SMESH_subMesh*> _copyMeshSubM; // submeshes requesting mesh copying + set< SMESH_subMesh*> _copyGroupSubM; // submeshes requesting mesh copying + set< SMESH_subMesh*> _computedSubM; + + SMESHDS_SubMesh* _importMeshSubDS; // submesh storing a copy of _srcMesh + int _importMeshSubID; // id of _importMeshSubDS + + _ImportData(const SMESH_Mesh* srcMesh=0): + _srcMesh(srcMesh), _importMeshSubDS(0),_importMeshSubID(-1) {} + + void removeImportedMesh( SMESHDS_Mesh* meshDS ) + { + if ( !_importMeshSubDS ) return; + SMDS_ElemIteratorPtr eIt = _importMeshSubDS->GetElements(); + while ( eIt->more() ) + meshDS->RemoveFreeElement( eIt->next(), _importMeshSubDS, /*fromGroups=*/false ); + SMDS_NodeIteratorPtr nIt = _importMeshSubDS->GetNodes(); + while ( nIt->more() ) + meshDS->RemoveFreeNode( nIt->next(), _importMeshSubDS, /*fromGroups=*/false ); + _n2n.clear(); + _e2e.clear(); + } + void removeGroups( SMESH_subMesh* subM, const StdMeshers_ImportSource1D* srcHyp ) + { + if ( !srcHyp ) return; + SMESH_Mesh* tgtMesh = subM->GetFather(); + const SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS(); + const SMESHDS_Mesh* srcMeshDS = _srcMesh->GetMeshDS(); + vector* groups = + const_cast(srcHyp)->GetResultGroups(*srcMeshDS,*tgtMeshDS); + if ( groups ) + { + for ( unsigned i = 0; i < groups->size(); ++i ) + tgtMesh->RemoveGroup( groups->at(i)->GetGroupDS()->GetID() ); + groups->clear(); + } + } + void trackHypParams( SMESH_subMesh* sm, const StdMeshers_ImportSource1D* srcHyp ) + { + if ( !srcHyp ) return; + bool toCopyMesh, toCopyGroups; + srcHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups); + + if ( toCopyMesh )_copyMeshSubM.insert( sm ); + else _copyMeshSubM.erase( sm ); + + if ( toCopyGroups ) _copyGroupSubM.insert( sm ); + else _copyGroupSubM.erase( sm ); + } + }; + //================================================================================ + /*! + * Listener notified on events of an imported submesh + */ + class _Listener : public SMESH_subMeshEventListener + { + typedef map< SMESH_Mesh*, list< _ImportData > > TMesh2ImpData; + TMesh2ImpData _tgtMesh2ImportData; + + _Listener():SMESH_subMeshEventListener(/*isDeletable=*/false){} + + public: + // return poiter to a static listener + static _Listener* get() { static _Listener theListener; return &theListener; } + + //-------------------------------------------------------------------------------- + /*! + * \brief Find or create ImportData for given meshes + */ + static _ImportData* getImportData(const SMESH_Mesh* srcMesh, + SMESH_Mesh* tgtMesh) + { + list< _ImportData >& dList = get()->_tgtMesh2ImportData[tgtMesh]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + if ( d->_srcMesh == srcMesh ) + return &*d; + dList.push_back(_ImportData(srcMesh)); + return &dList.back(); + } + + //-------------------------------------------------------------------------------- + /*! + * \brief Remember an imported mesh and groups + * \param smDS - submesh DS holding the imported mesh + * \param sm - submesh computed by Import algo + * \param srcMeshDS - source mesh + * \param srcHyp - ImportSource hypothesis + */ + static _ImportData* storeImportSubmesh(SMESH_subMesh* importSub, + const SMESH_Mesh* srcMesh, + const StdMeshers_ImportSource1D* srcHyp) + { + // set listener to hear events of the submesh computed by "Import" algo + importSub->SetEventListener( get(), new _ListenerData(srcHyp), importSub ); + + // set a listener to hear events of the source mesh + SMESH_subMesh* smToNotify = importSub; + SMESH_subMesh* smToListen = srcMesh->GetSubMeshContaining(1); + importSub->SetEventListener + ( new SMESH_subMeshEventListener(/*isDeletable=*/true), + SMESH_subMeshEventListenerData::MakeData( smToNotify ), + smToListen ); + + // remeber the submesh + _ImportData* iData = _Listener::getImportData( srcMesh, importSub->GetFather()); + iData->_subM.insert( importSub ); + iData->trackHypParams( importSub, srcHyp ); + if ( !importSub->IsEmpty() ) + iData->_computedSubM.insert( importSub ); + if ( !iData->_copyMeshSubM.empty() && iData->_importMeshSubID < 1 ) + { + SMESH_Mesh* tgtMesh = importSub->GetFather(); + iData->_importMeshSubID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(),tgtMesh); + iData->_importMeshSubDS = tgtMesh->GetMeshDS()->NewSubMesh( iData->_importMeshSubID ); + } + if ( !importSub->IsEmpty() ) + iData->_computedSubM.insert( importSub ); + + return iData; + } + //-------------------------------------------------------------------------------- + /*! + * \brief mark sm as missing src hyp with valid groups + */ + static void waitHypModification(SMESH_subMesh* sm) + { + sm->SetEventListener + (get(), SMESH_subMeshEventListenerData::MakeData( sm, WAIT_HYP_MODIF ), sm); + } + + //-------------------------------------------------------------------------------- + /*! + * \brief Remove imported mesh and/or groups as soon as no more imported submeshes + * remain computed + * \param sm - submesh loosing Import algo + * \param data - data holding imported groups + */ + void removeSubmesh( SMESH_subMesh* sm, _ListenerData* data ) + { + list< _ImportData > & dList = _tgtMesh2ImportData[ sm->GetFather() ]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + if ( (*d)._subM.erase( sm )) + { + d->_computedSubM.erase( sm ); + bool rmMesh = d->_copyMeshSubM.erase( sm ) && d->_copyMeshSubM.empty(); + bool rmGroups = (d->_copyGroupSubM.erase( sm ) && d->_copyGroupSubM.empty()) || rmMesh; + if ( rmMesh ) + d->removeImportedMesh( sm->GetFather()->GetMeshDS() ); + if ( rmGroups && data ) + d->removeGroups( sm, data->_srcHyp ); + } + } + //-------------------------------------------------------------------------------- + /*! + * \brief Remove imported mesh and/or groups and + * clear all submeshes with common source mesh + * \param sm - cleared submesh + * \param data - data holding imported groups + */ + void clearSubmesh( SMESH_subMesh* sm, _ListenerData* data ) + { + list< _ImportData > & dList = _tgtMesh2ImportData[ sm->GetFather() ]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + { + if ( !d->_subM.count( sm )) continue; + if ( (*d)._computedSubM.erase( sm ) ) + { + bool copyMesh = !d->_copyMeshSubM.empty(); + if ( copyMesh ) + { + // clear submeshes + if ( !d->_computedSubM.empty() ) + { + set< SMESH_subMesh*> subs; + subs.swap( d->_computedSubM ); // avoid recursion via events + while ( !subs.empty() ) + { + SMESH_subMesh* subM = *subs.begin(); subs.erase( subs.begin() ); + _ListenerData* hypData = (_ListenerData*) subM->GetEventListenerData( get() ); + if ( hypData ) + d->removeGroups( sm, hypData->_srcHyp ); + + subM->ComputeStateEngine( SMESH_subMesh::CLEAN ); + } + } + // remove imported mesh and groups + d->removeImportedMesh( sm->GetFather()->GetMeshDS() ); + + if ( data ) + d->removeGroups( sm, data->_srcHyp ); + } + } + if ( data ) + d->trackHypParams( sm, data->_srcHyp ); + d->_n2n.clear(); + d->_e2e.clear(); + } + } + //-------------------------------------------------------------------------------- + /*! + * \brief Remove imported mesh and/or groups + */ + virtual void ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMesh, + SMESH_subMeshEventListenerData* data, + const SMESH_Hypothesis* /*hyp*/) + { + if ( data && data->myType == WAIT_HYP_MODIF ) + { + if ( SMESH_subMesh::MODIF_HYP == event && + SMESH_subMesh::ALGO_EVENT == eventType ) + { + SMESH_Gen* gen = subMesh->GetFather()->GetGen(); + if ( SMESH_Algo* algo = gen->GetAlgo(*subMesh->GetFather(), subMesh->GetSubShape())) + algo->SetEventListener( subMesh ); + } + } + else + { + SMESH_Gen* gen = subMesh->GetFather()->GetGen(); + SMESH_Algo* algo = gen->GetAlgo(*subMesh->GetFather(),subMesh->GetSubShape() ); + + if ( subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK || + strncmp( "Import", algo->GetName(), 6 ) != 0 ) + { + // treate removal of Import algo from subMesh + removeSubmesh( subMesh, (_ListenerData*) data ); + } + else if ( subMesh->IsEmpty() ) + { + // treate modification of ImportSource hypothesis + clearSubmesh( subMesh, (_ListenerData*) data ); + } + else if ( SMESH_subMesh::CHECK_COMPUTE_STATE == event && + SMESH_subMesh::COMPUTE_EVENT == eventType ) + { + // check compute state of all submeshes impoting from same src mesh; + // this is to take into account 1D computed submeshes hidden by 2D import algo; + // else source mesh is not copied as _subM.size != _computedSubM.size() + list< _ImportData > & dList = _tgtMesh2ImportData[ subMesh->GetFather() ]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + if ( d->_subM.count( subMesh )) + { + set::iterator smIt = d->_subM.begin(); + for( ; smIt != d->_subM.end(); ++smIt ) + if ( (*smIt)->IsMeshComputed() ) + d->_computedSubM.insert( *smIt); + } + } + } + } + }; // class _Listener + + //================================================================================ + /*! + * \brief Return an ID of submesh to store nodes and elements of a copied mesh + */ + //================================================================================ + + int getSubmeshIDForCopiedMesh(const SMESHDS_Mesh* srcMeshDS, + SMESH_Mesh* tgtMesh) + { + // To get SMESH_subMesh corresponding to srcMeshDS we need to have a shape + // for which SMESHDS_Mesh::IsGroupOfSubShapes() returns true. + // And this shape must be different from subshapes of the main shape. + // So we create a compound containing + // 1) some sub-shapes of SMESH_Mesh::PseudoShape() corresponding to + // srcMeshDS->GetPersistentId() + // 2) the 1-st vertex of the main shape to assure + // SMESHDS_Mesh::IsGroupOfSubShapes(shape)==true + TopoDS_Shape shapeForSrcMesh; + TopTools_IndexedMapOfShape pseudoSubShapes; + TopExp::MapShapes( SMESH_Mesh::PseudoShape(), pseudoSubShapes ); + + // index of pseudoSubShapes corresponding to srcMeshDS + int subIndex = srcMeshDS->GetPersistentId() % pseudoSubShapes.Extent(); + int nbSubShapes = 1 + srcMeshDS->GetPersistentId() / pseudoSubShapes.Extent(); + + // try to find already present shapeForSrcMesh + SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS(); + for ( int i = tgtMeshDS->MaxShapeIndex(); i > 0 && shapeForSrcMesh.IsNull(); --i ) + { + const TopoDS_Shape& s = tgtMeshDS->IndexToShape(i); + if ( s.ShapeType() != TopAbs_COMPOUND ) break; + TopoDS_Iterator sSubIt( s ); + for ( int iSub = 0; iSub < nbSubShapes && sSubIt.More(); ++iSub, sSubIt.Next() ) + if ( pseudoSubShapes( subIndex+iSub ).IsSame( sSubIt.Value())) + if ( iSub+1 == nbSubShapes ) + { + shapeForSrcMesh = s; + break; + } + } + if ( shapeForSrcMesh.IsNull() ) + { + // make a new shapeForSrcMesh + BRep_Builder aBuilder; + TopoDS_Compound comp; + aBuilder.MakeCompound( comp ); + shapeForSrcMesh = comp; + for ( int iSub = 0; iSub < nbSubShapes; ++iSub ) + aBuilder.Add( comp, pseudoSubShapes( subIndex+iSub )); + TopExp_Explorer vExp( tgtMeshDS->ShapeToMesh(), TopAbs_VERTEX ); + aBuilder.Add( comp, vExp.Current() ); + } + SMESH_subMesh* sm = tgtMesh->GetSubMesh( shapeForSrcMesh ); + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + if ( !smDS ) + smDS = tgtMeshDS->NewSubMesh( sm->GetId() ); + + // make ordinary submesh from a complex one + if ( smDS->IsComplexSubmesh() ) + { + list< const SMESHDS_SubMesh* > subSM; + SMESHDS_SubMeshIteratorPtr smIt = smDS->GetSubMeshIterator(); + while ( smIt->more() ) subSM.push_back( smIt->next() ); + list< const SMESHDS_SubMesh* >::iterator sub = subSM.begin(); + for ( ; sub != subSM.end(); ++sub) + smDS->RemoveSubMesh( *sub ); + } + return sm->GetId(); + } + + //================================================================================ + /*! + * \brief Return a submesh to store nodes and elements of a copied mesh + * and set event listeners in order to clear + * imported mesh and groups as soon as submesh state requires it + */ + //================================================================================ + + SMESHDS_SubMesh* getSubmeshForCopiedMesh(const SMESH_Mesh* srcMesh, + SMESH_Mesh* tgtMesh, + const TopoDS_Shape& tgtShape, + StdMeshers_Import_1D::TNodeNodeMap*& n2n, + StdMeshers_Import_1D::TElemElemMap*& e2e, + bool & toCopyGroups) + { + StdMeshers_Import_1D::getMaps( srcMesh, tgtMesh, n2n,e2e ); + + _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh); + + SMESH_subMesh* importedSM = tgtMesh->GetSubMesh( tgtShape ); + iData->_computedSubM.insert( importedSM ); + if ( iData->_computedSubM.size() != iData->_subM.size() ) + return 0; // not all submeshes computed yet + + toCopyGroups = !iData->_copyGroupSubM.empty(); + + if ( !iData->_copyMeshSubM.empty()) + { + // make submesh to store a copied mesh + int smID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(), tgtMesh ); + SMESHDS_SubMesh* subDS = tgtMesh->GetMeshDS()->NewSubMesh( smID ); + + iData->_importMeshSubID = smID; + iData->_importMeshSubDS = subDS; + return subDS; + } + return 0; + } + +} // namespace + + +//============================================================================= +/*! + * Import elements from the other mesh + */ +//============================================================================= + +bool StdMeshers_Import_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & theShape) +{ + if ( !_sourceHyp ) return false; + + const vector& srcGroups = _sourceHyp->GetGroups(); + if ( srcGroups.empty() ) + return error("Invalid source groups"); + + SMESH_MesherHelper helper(theMesh); + helper.SetSubShape(theShape); + SMESHDS_Mesh* tgtMesh = theMesh.GetMeshDS(); + + const TopoDS_Edge& geomEdge = TopoDS::Edge( theShape ); + const double edgeTol = BRep_Tool::Tolerance( geomEdge ); + const int shapeID = tgtMesh->ShapeToIndex( geomEdge ); + + set subShapeIDs; + subShapeIDs.insert( shapeID ); + + // get nodes on vertices + list < SMESH_MeshEditor::TNodeXYZ > vertexNodes; + list < SMESH_MeshEditor::TNodeXYZ >::iterator vNIt; + TopExp_Explorer vExp( theShape, TopAbs_VERTEX ); + for ( ; vExp.More(); vExp.Next() ) + { + const TopoDS_Vertex& v = TopoDS::Vertex( vExp.Current() ); + if ( !subShapeIDs.insert( tgtMesh->ShapeToIndex( v )).second ) + continue; // closed edge + const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh ); + if ( !n ) + { + _gen->Compute(theMesh,v,/*anUpward=*/true); + n = SMESH_Algo::VertexNode( v, tgtMesh ); + if ( !n ) return false; // very strange + } + vertexNodes.push_back( SMESH_MeshEditor::TNodeXYZ( n )); + } + + // import edges from groups + TNodeNodeMap* n2n; + TElemElemMap* e2e; + for ( int iG = 0; iG < srcGroups.size(); ++iG ) + { + const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS(); + + const int meshID = srcGroup->GetMesh()->GetPersistentId(); + const SMESH_Mesh* srcMesh = GetMeshByPersistentID( meshID ); + if ( !srcMesh ) continue; + getMaps( srcMesh, &theMesh, n2n, e2e ); + + SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements(); + vector newNodes; + SMDS_MeshNode tmpNode(0,0,0); + double u; + while ( srcElems->more() ) // loop on group contents + { + const SMDS_MeshElement* edge = srcElems->next(); + // find or create nodes of a new edge + newNodes.resize( edge->NbNodes() ); + newNodes.back() = 0; + SMDS_MeshElement::iterator node = edge->begin_nodes(); + for ( unsigned i = 0; i < newNodes.size(); ++i, ++node ) + { + TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )).first; + if ( n2nIt->second ) + { + if ( !subShapeIDs.count( n2nIt->second->GetPosition()->GetShapeId() )) + break; + } + else + { + // find an existing vertex node + for ( vNIt = vertexNodes.begin(); vNIt != vertexNodes.end(); ++vNIt) + if ( vNIt->SquareDistance( *node ) < 10 * edgeTol * edgeTol) + { + (*n2nIt).second = vNIt->_node; + vertexNodes.erase( vNIt ); + break; + } + } + if ( !n2nIt->second ) + { + // find out if node lies on theShape + tmpNode.setXYZ( (*node)->X(), (*node)->Y(), (*node)->Z()); + if ( helper.CheckNodeU( geomEdge, &tmpNode, u, 10 * edgeTol, /*force=*/true )) + { + SMDS_MeshNode* newNode = tgtMesh->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z()); + n2nIt->second = newNode; + tgtMesh->SetNodeOnEdge( newNode, shapeID, u ); + } + } + if ( !(newNodes[i] = n2nIt->second )) + break; + } + if ( !newNodes.back() ) + continue; // not all nodes of edge lie on theShape + + // make a new edge + SMDS_MeshElement * newEdge; + if ( newNodes.size() == 3 ) + newEdge = tgtMesh->AddEdge( newNodes[0], newNodes[1], newNodes[2] ); + else + newEdge = tgtMesh->AddEdge( newNodes[0], newNodes[1]); + tgtMesh->SetMeshElementOnShape( newEdge, shapeID ); + e2e->insert( make_pair( edge, newEdge )); + } + } + if ( n2n->empty()) + return error("Empty source groups"); + + // check if the whole geom edge is covered by imported segments; + // the check consist in passing by segments from one vetrex node to another + bool isEdgeMeshed = false; + if ( SMESHDS_SubMesh* tgtSM = tgtMesh->MeshElements( theShape )) + { + const TopoDS_Vertex& v = ( vExp.ReInit(), TopoDS::Vertex( vExp.Current() )); + const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh ); + const SMDS_MeshElement* seg = 0; + SMDS_ElemIteratorPtr segIt = n->GetInverseElementIterator(SMDSAbs_Edge); + while ( segIt->more() && !seg ) + if ( !tgtSM->Contains( seg = segIt->next())) + seg = 0; + int nbPassedSegs = 0; + while ( seg ) + { + ++nbPassedSegs; + const SMDS_MeshNode* n2 = seg->GetNode(0); + n = ( n2 == n ? seg->GetNode(1) : n2 ); + if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + break; + const SMDS_MeshElement* seg2 = 0; + segIt = n->GetInverseElementIterator(SMDSAbs_Edge); + while ( segIt->more() && !seg2 ) + if ( seg == ( seg2 = segIt->next())) + seg2 = 0; + seg = seg2; + } + if (nbPassedSegs > 0 && tgtSM->NbElements() > nbPassedSegs ) + return error( "Source elements overlap one another"); + + isEdgeMeshed = ( tgtSM->NbElements() == nbPassedSegs && + n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ); + } + if ( !isEdgeMeshed ) + return error( "Source elements don't cover totally the geometrical edge" ); + + // copy meshes + vector srcMeshes = _sourceHyp->GetSourceMeshes(); + for ( unsigned i = 0; i < srcMeshes.size(); ++i ) + importMesh( srcMeshes[i], theMesh, _sourceHyp, theShape ); + + return true; +} + +//================================================================================ +/*! + * \brief Copy mesh and groups + */ +//================================================================================ + +void StdMeshers_Import_1D::importMesh(const SMESH_Mesh* srcMesh, + SMESH_Mesh & tgtMesh, + StdMeshers_ImportSource1D* srcHyp, + const TopoDS_Shape& tgtShape) +{ + // get submesh to store the imported mesh + TNodeNodeMap* n2n; + TElemElemMap* e2e; + bool toCopyGroups; + SMESHDS_SubMesh* tgtSubMesh = + getSubmeshForCopiedMesh( srcMesh, &tgtMesh, tgtShape, n2n, e2e, toCopyGroups ); + if ( !tgtSubMesh || tgtSubMesh->NbNodes() + tgtSubMesh->NbElements() > 0 ) + return; // not to copy srcMeshDS twice + + SMESHDS_Mesh* tgtMeshDS = tgtMesh.GetMeshDS(); + SMESH_MeshEditor additor( &tgtMesh ); + + // 1. Copy mesh + + vector newNodes; + const SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS(); + SMDS_ElemIteratorPtr eIt = srcMeshDS->elementsIterator(); + while ( eIt->more() ) + { + const SMDS_MeshElement* elem = eIt->next(); + TElemElemMap::iterator e2eIt = e2e->insert( make_pair( elem, (SMDS_MeshElement*)0 )).first; + if ( e2eIt->second ) continue; // already copied by Compute() + newNodes.resize( elem->NbNodes() ); + SMDS_MeshElement::iterator node = elem->begin_nodes(); + for ( unsigned i = 0; i < newNodes.size(); ++i, ++node ) + { + TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )).first; + if ( !n2nIt->second ) + { + (*n2nIt).second = tgtMeshDS->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z()); + tgtSubMesh->AddNode( n2nIt->second ); + } + newNodes[i] = n2nIt->second; + } + const SMDS_MeshElement* newElem = + tgtMeshDS->FindElement( newNodes, elem->GetType(), /*noMedium=*/false ); + if ( !newElem ) + { + newElem = additor.AddElement( newNodes, elem->GetType(), elem->IsPoly()); + tgtSubMesh->AddElement( newElem ); + } + if ( toCopyGroups ) + (*e2eIt).second = newElem; + } + // copy free nodes + if ( srcMeshDS->NbNodes() > n2n->size() ) + { + SMDS_NodeIteratorPtr nIt = srcMeshDS->nodesIterator(); + while( nIt->more() ) + { + const SMDS_MeshNode* node = nIt->next(); + if ( node->NbInverseElements() == 0 ) + { + const SMDS_MeshNode* newNode = tgtMeshDS->AddNode( node->X(), node->Y(), node->Z()); + n2n->insert( make_pair( node, newNode )); + tgtSubMesh->AddNode( newNode ); + } + } + } + + // 2. Copy groups + + vector resultGroups; + if ( toCopyGroups ) + { + // collect names of existing groups to assure uniqueness of group names within a type + map< SMDSAbs_ElementType, set > namesByType; + SMESH_Mesh::GroupIteratorPtr groupIt = tgtMesh.GetGroups(); + while ( groupIt->more() ) + { + SMESH_Group* tgtGroup = groupIt->next(); + namesByType[ tgtGroup->GetGroupDS()->GetType() ].insert( tgtGroup->GetName() ); + } + if (srcMesh) + { + SMESH_Mesh::GroupIteratorPtr groupIt = srcMesh->GetGroups(); + while ( groupIt->more() ) + { + SMESH_Group* srcGroup = groupIt->next(); + SMESHDS_GroupBase* srcGroupDS = srcGroup->GetGroupDS(); + string name = srcGroup->GetName(); + int nb = 1; + while ( !namesByType[ srcGroupDS->GetType() ].insert( name ).second ) + name = SMESH_Comment(srcGroup->GetName()) << "_imported_" << nb++; + SMESH_Group* newGroup = tgtMesh.AddGroup( srcGroupDS->GetType(), name.c_str(), nb ); + SMESHDS_Group* newGroupDS = (SMESHDS_Group*)newGroup->GetGroupDS(); + resultGroups.push_back( newGroup ); + + eIt = srcGroupDS->GetElements(); + if ( srcGroupDS->GetType() == SMDSAbs_Node ) + while (eIt->more()) + { + TNodeNodeMap::iterator n2nIt = n2n->find((const SMDS_MeshNode*) eIt->next() ); + if ( n2nIt != n2n->end() && n2nIt->second ) + newGroupDS->SMDSGroup().Add((*n2nIt).second ); + } + else + while (eIt->more()) + { + TElemElemMap::iterator e2eIt = e2e->find( eIt->next() ); + if ( e2eIt != e2e->end() && e2eIt->second ) + newGroupDS->SMDSGroup().Add((*e2eIt).second ); + } + } + } + } + n2n->clear(); + e2e->clear(); + + // Remember created groups in order to remove them as soon as the srcHyp is + // modified or something other similar happens. Store them in a hypothesis + // as it stores its values anyway + srcHyp->StoreResultGroups( resultGroups, *srcMeshDS, *tgtMeshDS ); +} + +//============================================================================= +/*! + * \brief Set needed event listeners and create a submesh for a copied mesh + * + * This method is called only if a submesh has HYP_OK algo_state. + */ +//============================================================================= + +void StdMeshers_Import_1D::setEventListener(SMESH_subMesh* subMesh, + StdMeshers_ImportSource1D* sourceHyp) +{ + if ( sourceHyp ) + { + vector srcMeshes = sourceHyp->GetSourceMeshes(); + if ( srcMeshes.empty() ) + _Listener::waitHypModification( subMesh ); + for ( unsigned i = 0; i < srcMeshes.size(); ++i ) + // set a listener to remove the imported mesh and groups + _Listener::storeImportSubmesh( subMesh, srcMeshes[i], sourceHyp ); + } +} +void StdMeshers_Import_1D::SetEventListener(SMESH_subMesh* subMesh) +{ + if ( !_sourceHyp ) + { + const TopoDS_Shape& tgtShape = subMesh->GetSubShape(); + SMESH_Mesh* tgtMesh = subMesh->GetFather(); + Hypothesis_Status aStatus; + CheckHypothesis( *tgtMesh, tgtShape, aStatus ); + } + setEventListener( subMesh, _sourceHyp ); +} + +void StdMeshers_Import_1D::SubmeshRestored(SMESH_subMesh* subMesh) +{ + SetEventListener(subMesh); +} + +//============================================================================= +/*! + * Predict nb of mesh entities created by Compute() + */ +//============================================================================= + +bool StdMeshers_Import_1D::Evaluate(SMESH_Mesh & theMesh, + const TopoDS_Shape & theShape, + MapShapeNbElems& aResMap) +{ + if ( !_sourceHyp ) return false; + + const vector& srcGroups = _sourceHyp->GetGroups(); + if ( srcGroups.empty() ) + return error("Invalid source groups"); + + vector aVec(SMDSEntity_Last,0); + + bool toCopyMesh, toCopyGroups; + _sourceHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups); + if ( toCopyMesh ) // the whole mesh is copied + { + vector srcMeshes = _sourceHyp->GetSourceMeshes(); + for ( unsigned i = 0; i < srcMeshes.size(); ++i ) + { + SMESH_subMesh* sm = getSubMeshOfCopiedMesh( theMesh, *srcMeshes[i]); + if ( !sm || aResMap.count( sm )) continue; // already counted + aVec.assign( SMDSEntity_Last, 0); + const SMDS_MeshInfo& aMeshInfo = srcMeshes[i]->GetMeshDS()->GetMeshInfo(); + for (int i = 0; i < SMDSEntity_Last; i++) + aVec[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i); + } + } + else + { + SMESH_MesherHelper helper(theMesh); + + const TopoDS_Edge& geomEdge = TopoDS::Edge( theShape ); + const double edgeTol = helper.MaxTolerance( geomEdge ); + + // take into account nodes on vertices + TopExp_Explorer vExp( theShape, TopAbs_VERTEX ); + for ( ; vExp.More(); vExp.Next() ) + theMesh.GetSubMesh( vExp.Current())->Evaluate( aResMap ); + + // count edges imported from groups + int nbEdges = 0, nbQuadEdges = 0; + for ( int iG = 0; iG < srcGroups.size(); ++iG ) + { + const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS(); + SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements(); + SMDS_MeshNode tmpNode(0,0,0); + while ( srcElems->more() ) // loop on group contents + { + const SMDS_MeshElement* edge = srcElems->next(); + // find out if edge is located on geomEdge by projecting + // a middle of edge to geomEdge + SMESH_MeshEditor::TNodeXYZ p1( edge->GetNode(0)); + SMESH_MeshEditor::TNodeXYZ p2( edge->GetNode(1)); + gp_XYZ middle = ( p1 + p2 ) / 2.; + tmpNode.setXYZ( middle.X(), middle.Y(), middle.Z()); + double u = 0; + if ( helper.CheckNodeU( geomEdge, &tmpNode, u, 10 * edgeTol, /*force=*/true )) + ++( edge->IsQuadratic() ? nbQuadEdges : nbEdges); + } + } + + int nbNodes = nbEdges + 2 * nbQuadEdges - 1; + + aVec[SMDSEntity_Node ] = nbNodes; + aVec[SMDSEntity_Edge ] = nbEdges; + aVec[SMDSEntity_Quad_Edge] = nbQuadEdges; + } + + SMESH_subMesh * sm = theMesh.GetSubMesh(theShape); + aResMap.insert(make_pair(sm,aVec)); + + return true; +} + +//================================================================================ +/*! + * \brief Return node-node and element-element maps for import of geiven source mesh + */ +//================================================================================ + +void StdMeshers_Import_1D::getMaps(const SMESH_Mesh* srcMesh, + SMESH_Mesh* tgtMesh, + TNodeNodeMap*& n2n, + TElemElemMap*& e2e) +{ + _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh); + n2n = &iData->_n2n; + e2e = &iData->_e2e; + if ( iData->_copyMeshSubM.empty() ) + { + n2n->clear(); + e2e->clear(); + } +} + +//================================================================================ +/*! + * \brief Return submesh corresponding to the copied mesh + */ +//================================================================================ + +SMESH_subMesh* StdMeshers_Import_1D::getSubMeshOfCopiedMesh( SMESH_Mesh& tgtMesh, + SMESH_Mesh& srcMesh ) +{ + _ImportData* iData = _Listener::getImportData(&srcMesh,&tgtMesh); + if ( iData->_copyMeshSubM.empty() ) return 0; + SMESH_subMesh* sm = tgtMesh.GetSubMeshContaining( iData->_importMeshSubID ); + return sm; +} + diff --git a/src/StdMeshers/StdMeshers_Import_1D.hxx b/src/StdMeshers/StdMeshers_Import_1D.hxx new file mode 100644 index 000000000..a3ab382fb --- /dev/null +++ b/src/StdMeshers/StdMeshers_Import_1D.hxx @@ -0,0 +1,81 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// Module : SMESH +// +#ifndef _SMESH_Import_1D_HXX_ +#define _SMESH_Import_1D_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_1D_Algo.hxx" +#include "SMDS_MeshElement.hxx" + +class StdMeshers_ImportSource1D; + +/*! + * \brief Copy elements from other the mesh + */ +class STDMESHERS_EXPORT StdMeshers_Import_1D: public SMESH_1D_Algo +{ +public: + StdMeshers_Import_1D(int hypId, int studyId, SMESH_Gen* gen); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + virtual bool Compute (SMESH_Mesh & aMesh, const TopoDS_Shape & aShape); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + + virtual void SetEventListener(SMESH_subMesh* subMesh); + virtual void SubmeshRestored(SMESH_subMesh* subMesh); + + // internal utilities + + typedef std::map TNodeNodeMap; + typedef std::map TElemElemMap; + + static void getMaps(const SMESH_Mesh* srcMesh, + SMESH_Mesh* tgtMesh, + TNodeNodeMap*& n2n, + TElemElemMap*& e2e); + + static void importMesh(const SMESH_Mesh* srcMesh, + SMESH_Mesh & tgtMesh, + StdMeshers_ImportSource1D* srcHyp, + const TopoDS_Shape& tgtShape); + + static void setEventListener( SMESH_subMesh* subMesh, + StdMeshers_ImportSource1D* sourceHyp ); + + static SMESH_subMesh* getSubMeshOfCopiedMesh( SMESH_Mesh& tgtMesh, + SMESH_Mesh& srcMesh ); + + private: + + StdMeshers_ImportSource1D* _sourceHyp; +}; + +#endif diff --git a/src/StdMeshers/StdMeshers_Import_1D2D.cxx b/src/StdMeshers/StdMeshers_Import_1D2D.cxx new file mode 100644 index 000000000..5513a1077 --- /dev/null +++ b/src/StdMeshers/StdMeshers_Import_1D2D.cxx @@ -0,0 +1,643 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// File : StdMeshers_Import_1D2D.cxx +// Module : SMESH +// +#include "StdMeshers_Import_1D2D.hxx" + +#include "StdMeshers_Import_1D.hxx" +#include "StdMeshers_ImportSource.hxx" + +#include "SMDS_MeshElement.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMESHDS_Group.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_Comment.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Group.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_subMesh.hxx" + +#include "Utils_SALOME_Exception.hxx" +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +//============================================================================= +/*! + * Creates StdMeshers_Import_1D2D + */ +//============================================================================= + +StdMeshers_Import_1D2D::StdMeshers_Import_1D2D(int hypId, int studyId, SMESH_Gen * gen) + :SMESH_2D_Algo(hypId, studyId, gen), _sourceHyp(0) +{ + MESSAGE("StdMeshers_Import_1D2D::StdMeshers_Import_1D2D"); + _name = "Import_1D2D"; + _shapeType = (1 << TopAbs_FACE); + + _compatibleHypothesis.push_back("ImportSource2D"); + _requireDescretBoundary = false; +} + +//============================================================================= +/*! + * Check presence of a hypothesis + */ +//============================================================================= + +bool StdMeshers_Import_1D2D::CheckHypothesis + (SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus) +{ + _sourceHyp = 0; + + const list &hyps = GetUsedHypothesis(aMesh, aShape); + if ( hyps.size() == 0 ) + { + aStatus = SMESH_Hypothesis::HYP_MISSING; + return false; // can't work with no hypothesis + } + + if ( hyps.size() > 1 ) + { + aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST; + return false; + } + + const SMESHDS_Hypothesis *theHyp = hyps.front(); + + string hypName = theHyp->GetName(); + + if (hypName == _compatibleHypothesis.front()) + { + _sourceHyp = (StdMeshers_ImportSource1D *)theHyp; + aStatus = SMESH_Hypothesis::HYP_OK; + return true; + } + + aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + return true; +} + +namespace +{ + /*! + * \brief OrientedLink additionally storing a medium node + */ + struct TLink : public SMESH_OrientedLink + { + const SMDS_MeshNode* _medium; + TLink( const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const SMDS_MeshNode* medium=0) + : SMESH_OrientedLink( n1,n2 ), _medium( medium ) {} + }; +} + +//============================================================================= +/*! + * Import elements from the other mesh + */ +//============================================================================= + +bool StdMeshers_Import_1D2D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & theShape) +{ + if ( !_sourceHyp ) return false; + + const vector& srcGroups = _sourceHyp->GetGroups(); + if ( srcGroups.empty() ) + return error("Invalid source groups"); + + SMESH_MesherHelper helper(theMesh); + helper.SetSubShape(theShape); + SMESHDS_Mesh* tgtMesh = theMesh.GetMeshDS(); + + const TopoDS_Face& geomFace = TopoDS::Face( theShape ); + const double faceTol = helper.MaxTolerance( geomFace ); + const int shapeID = tgtMesh->ShapeToIndex( geomFace ); + const bool toCheckOri = (helper.NbAncestors( geomFace, theMesh, TopAbs_SOLID ) == 1 ); + + Handle(Geom_Surface) surface = BRep_Tool::Surface( geomFace ); + if ( helper.GetSubShapeOri( tgtMesh->ShapeToMesh(), geomFace) == TopAbs_REVERSED ) + surface->UReverse(); + gp_Pnt p; gp_Vec du, dv; + + set subShapeIDs; + subShapeIDs.insert( shapeID ); + + // get nodes on vertices + list < SMESH_MeshEditor::TNodeXYZ > vertexNodes; + list < SMESH_MeshEditor::TNodeXYZ >::iterator vNIt; + TopExp_Explorer exp( theShape, TopAbs_VERTEX ); + for ( ; exp.More(); exp.Next() ) + { + const TopoDS_Vertex& v = TopoDS::Vertex( exp.Current() ); + if ( !subShapeIDs.insert( tgtMesh->ShapeToIndex( v )).second ) + continue; + const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, tgtMesh ); + if ( !n ) + { + _gen->Compute(theMesh,v,/*anUpward=*/true); + n = SMESH_Algo::VertexNode( v, tgtMesh ); + if ( !n ) return false; // very strange + } + vertexNodes.push_back( SMESH_MeshEditor::TNodeXYZ( n )); + } + + // to count now many times a link between nodes encounters + map linkCount; + map::iterator link2Nb; + + // ========================= + // Import faces from groups + // ========================= + + StdMeshers_Import_1D::TNodeNodeMap* n2n; + StdMeshers_Import_1D::TElemElemMap* e2e; + vector newNodes; + for ( int iG = 0; iG < srcGroups.size(); ++iG ) + { + const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS(); + + const int meshID = srcGroup->GetMesh()->GetPersistentId(); + const SMESH_Mesh* srcMesh = GetMeshByPersistentID( meshID ); + if ( !srcMesh ) continue; + StdMeshers_Import_1D::getMaps( srcMesh, &theMesh, n2n, e2e ); + + SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements(); + SMDS_MeshNode tmpNode(0,0,0); + gp_XY uv; + while ( srcElems->more() ) // loop on group contents + { + const SMDS_MeshElement* face = srcElems->next(); + // find or create nodes of a new face + newNodes.resize( face->NbNodes() ); + newNodes.back() = 0; + int nbCreatedNodes = 0; + SMDS_MeshElement::iterator node = face->begin_nodes(); + for ( unsigned i = 0; i < newNodes.size(); ++i, ++node ) + { + TNodeNodeMap::iterator n2nIt = n2n->insert( make_pair( *node, (SMDS_MeshNode*)0 )).first; + if ( n2nIt->second ) + { + if ( !subShapeIDs.count( n2nIt->second->GetPosition()->GetShapeId() )) + break; + } + else + { + // find an existing vertex node + for ( vNIt = vertexNodes.begin(); vNIt != vertexNodes.end(); ++vNIt) + if ( vNIt->SquareDistance( *node ) < 10 * faceTol * faceTol) + { + (*n2nIt).second = vNIt->_node; + vertexNodes.erase( vNIt ); + break; + } + } + if ( !n2nIt->second ) + { + // find out if node lies on theShape + tmpNode.setXYZ( (*node)->X(), (*node)->Y(), (*node)->Z()); + if ( helper.CheckNodeUV( geomFace, &tmpNode, uv, 10 * faceTol, /*force=*/true )) + { + SMDS_MeshNode* newNode = tgtMesh->AddNode( (*node)->X(), (*node)->Y(), (*node)->Z()); + n2nIt->second = newNode; + tgtMesh->SetNodeOnFace( newNode, shapeID, uv.X(), uv.Y() ); + nbCreatedNodes++; + } + } + if ( !(newNodes[i] = n2nIt->second )) + break; + } + if ( !newNodes.back() ) + continue; // not all nodes of the face lie on theShape + + // try to find already created face + SMDS_MeshElement * newFace = 0; + if ( nbCreatedNodes == 0 && + tgtMesh->FindElement(newNodes, SMDSAbs_Face, /*noMedium=*/false)) + continue; // repeated face in source groups already created + + // check future face orientation + if ( toCheckOri ) + { + int iNode = -1; + gp_Vec geomNorm; + do + { + uv = helper.GetNodeUV( geomFace, newNodes[++iNode] ); + surface->D1( uv.X(),uv.Y(), p, du,dv ); + geomNorm = du ^ dv; + } + while ( geomNorm.SquareMagnitude() < 1e-6 && iNode+1 < face->NbCornerNodes()); + + int iNext = helper.WrapIndex( iNode+1, face->NbCornerNodes() ); + int iPrev = helper.WrapIndex( iNode-1, face->NbCornerNodes() ); + + SMESH_MeshEditor::TNodeXYZ prevNode( newNodes[iPrev] ); + SMESH_MeshEditor::TNodeXYZ curNode ( newNodes[iNode] ); + SMESH_MeshEditor::TNodeXYZ nextNode( newNodes[iNext] ); + gp_Vec n1n0( prevNode - curNode); + gp_Vec n1n2( nextNode - curNode ); + gp_Vec meshNorm = n1n2 ^ n1n0; + + if ( geomNorm * meshNorm < 0 ) + std::reverse( newNodes.begin(), newNodes.end() ); + } + + // make a new face + switch ( newNodes.size() ) + { + case 3: + newFace = tgtMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] ); + break; + case 4: + newFace = tgtMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] ); + break; + case 6: + newFace = tgtMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], + newNodes[3], newNodes[4], newNodes[5]); + break; + case 8: + newFace = tgtMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3], + newNodes[4], newNodes[5], newNodes[6], newNodes[7]); + break; + default: continue; + } + tgtMesh->SetMeshElementOnShape( newFace, shapeID ); + e2e->insert( make_pair( face, newFace )); + + // collect links + int nbNodes = face->NbCornerNodes(); + const SMDS_MeshNode* medium = 0; + for ( int i = 0; i < nbNodes; ++i ) + { + const SMDS_MeshNode* n1 = newNodes[i]; + const SMDS_MeshNode* n2 = newNodes[ (i+1)%nbNodes ]; + if ( newFace->IsQuadratic() ) + medium = newNodes[i+nbNodes]; + link2Nb = linkCount.insert( make_pair( TLink( n1, n2, medium ), 0)).first; + ++link2Nb->second; + } + } + } + + // ========================================================== + // Put nodes on geom edges and create edges on them; + // check if the whole geom face is covered by imported faces + // ========================================================== + + vector< TopoDS_Edge > edges; + for ( exp.Init( theShape, TopAbs_EDGE ); exp.More(); exp.Next() ) + if ( subShapeIDs.insert( tgtMesh->ShapeToIndex( exp.Current() )).second ) + edges.push_back( TopoDS::Edge( exp.Current() )); + + bool isFaceMeshed = false; + if ( SMESHDS_SubMesh* tgtSM = tgtMesh->MeshElements( theShape )) + { + // the imported mesh is valid if all external links (encountered once) + // lie on geom edges + subShapeIDs.erase( shapeID ); // to contain edges and vertices only + double u, f, l; + for ( link2Nb = linkCount.begin(); link2Nb != linkCount.end(); ++link2Nb) + { + const TLink& link = (*link2Nb).first; + int nbFaces = link2Nb->second; + if ( nbFaces == 1 ) + { + // check if the link lie on face boundary + bool nodesOnBoundary = true; + list< TopoDS_Shape > bndShapes; + for ( int is1stN = 0; is1stN < 2 && nodesOnBoundary; ++is1stN ) + { + const SMDS_MeshNode* n = is1stN ? link.node1() : link.node2(); + if ( !subShapeIDs.count( n->GetPosition()->GetShapeId() )) + { + for ( unsigned iE = 0; iE < edges.size(); ++iE ) + if ( helper.CheckNodeU( edges[iE], n, u, 10 * faceTol, /*force=*/true )) + { + BRep_Tool::Range(edges[iE],f,l); + if ( Abs(u-f) < 2 * faceTol || Abs(u-l) < 2 * faceTol ) + // duplicated node on vertex + return error("Source elements overlap one another"); + tgtMesh->SetNodeOnEdge( (SMDS_MeshNode*)n, edges[iE], u ); + break; + } + nodesOnBoundary = subShapeIDs.count( n->GetPosition()->GetShapeId()); + } + if ( nodesOnBoundary ) + { + TopoDS_Shape s = helper.GetSubShapeByNode( n, tgtMesh ); + if ( s.ShapeType() == TopAbs_VERTEX ) + bndShapes.push_front( s ); // vertex first + else + bndShapes.push_back( s ); // edges last + } + } + if ( !nodesOnBoundary ) + break; // free internal link + if ( bndShapes.front().ShapeType() == TopAbs_EDGE && + bndShapes.front() != bndShapes.back() ) + break; // link nodes on different geom edges + + // find geom edge the link is on + if ( bndShapes.back().ShapeType() != TopAbs_EDGE ) + { + // find geom edge by two vertices + TopoDS_Shape geomEdge; + PShapeIteratorPtr edgeIt = helper.GetAncestors( bndShapes.back(), theMesh, TopAbs_EDGE ); + while ( edgeIt->more() ) + { + geomEdge = *(edgeIt->next()); + if ( !helper.IsSubShape( bndShapes.front(), geomEdge )) + geomEdge.Nullify(); + } + if ( geomEdge.IsNull() ) + break; // vertices belong to different edges -> free internal link + bndShapes.push_back( geomEdge ); + } + + // create an edge if not yet exists + newNodes.resize(2); + newNodes[0] = link.node1(), newNodes[1] = link.node2(); + const SMDS_MeshElement* edge = tgtMesh->FindElement( newNodes, SMDSAbs_Edge ); + if ( edge ) continue; + + if ( link._reversed ) std::swap( newNodes[0], newNodes[1] ); + if ( link._medium ) + { + newNodes.push_back( link._medium ); + edge = tgtMesh->AddEdge( newNodes[0], newNodes[1], newNodes[2] ); + + TopoDS_Edge geomEdge = TopoDS::Edge(bndShapes.back()); + helper.CheckNodeU( geomEdge, link._medium, u, 10*faceTol, /*force=*/true ); + tgtMesh->SetNodeOnEdge( (SMDS_MeshNode*)link._medium, geomEdge, u ); + } + else + { + edge = tgtMesh->AddEdge( newNodes[0], newNodes[1]); + } + // remove nodes from submesh of theShape + for ( unsigned i = 0; i < newNodes.size(); ++i ) + tgtSM->RemoveNode( newNodes[i], /*isNodeDeleted=*/false ); + if ( !edge ) + return false; + + tgtMesh->SetMeshElementOnShape( edge, bndShapes.back() ); + } + else if ( nbFaces > 2 ) + { + return error( "Non-manifold source mesh"); + } + } + isFaceMeshed = ( link2Nb == linkCount.end() && !linkCount.empty()); + if ( isFaceMeshed ) + { + // check that source faces do not overlap: + // there must be only two edges sharing each vertex and bound to sub-edges of theShape + SMESH_MeshEditor editor( &theMesh ); + set::iterator subID = subShapeIDs.begin(); + for ( ; subID != subShapeIDs.end(); ++subID ) + { + const TopoDS_Shape& s = tgtMesh->IndexToShape( *subID ); + if ( s.ShapeType() != TopAbs_VERTEX ) continue; + const SMDS_MeshNode* n = SMESH_Algo::VertexNode( TopoDS::Vertex(s), tgtMesh ); + SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator(SMDSAbs_Edge); + int nbEdges = 0; + while ( eIt->more() ) + { + const SMDS_MeshElement* edge = eIt->next(); + int sId = editor.FindShape( edge ); + nbEdges += subShapeIDs.count( sId ); + } + if ( nbEdges < 2 ) + return false; // weird + if ( nbEdges > 2 ) + return error( "Source elements overlap one another"); + } + } + } + if ( !isFaceMeshed ) + return error( "Source elements don't cover totally the geometrical face" ); + + // notify sub-meshes of edges on computation + for ( unsigned iE = 0; iE < edges.size(); ++iE ) + theMesh.GetSubMesh( edges[iE] )->ComputeStateEngine(SMESH_subMesh::CHECK_COMPUTE_STATE); + + // ============ + // Copy meshes + // ============ + + vector srcMeshes = _sourceHyp->GetSourceMeshes(); + for ( unsigned i = 0; i < srcMeshes.size(); ++i ) + StdMeshers_Import_1D::importMesh( srcMeshes[i], theMesh, _sourceHyp, theShape ); + + return true; +} + +//============================================================================= +/*! + * \brief Set needed event listeners and create a submesh for a copied mesh + * + * This method is called only if a submesh has HYP_OK algo_state. + */ +//============================================================================= + +void StdMeshers_Import_1D2D::SetEventListener(SMESH_subMesh* subMesh) +{ + if ( !_sourceHyp ) + { + const TopoDS_Shape& tgtShape = subMesh->GetSubShape(); + SMESH_Mesh* tgtMesh = subMesh->GetFather(); + Hypothesis_Status aStatus; + CheckHypothesis( *tgtMesh, tgtShape, aStatus ); + } + StdMeshers_Import_1D::setEventListener( subMesh, _sourceHyp ); +} +void StdMeshers_Import_1D2D::SubmeshRestored(SMESH_subMesh* subMesh) +{ + SetEventListener(subMesh); +} + +//============================================================================= +/*! + * Predict nb of mesh entities created by Compute() + */ +//============================================================================= + +bool StdMeshers_Import_1D2D::Evaluate(SMESH_Mesh & theMesh, + const TopoDS_Shape & theShape, + MapShapeNbElems& aResMap) +{ + if ( !_sourceHyp ) return false; + + const vector& srcGroups = _sourceHyp->GetGroups(); + if ( srcGroups.empty() ) + return error("Invalid source groups"); + + vector aVec(SMDSEntity_Last,0); + + bool toCopyMesh, toCopyGroups; + _sourceHyp->GetCopySourceMesh(toCopyMesh, toCopyGroups); + if ( toCopyMesh ) // the whole mesh is copied + { + vector srcMeshes = _sourceHyp->GetSourceMeshes(); + for ( unsigned i = 0; i < srcMeshes.size(); ++i ) + { + SMESH_subMesh* sm = StdMeshers_Import_1D::getSubMeshOfCopiedMesh( theMesh, *srcMeshes[i]); + if ( !sm || aResMap.count( sm )) continue; // already counted + const SMDS_MeshInfo& aMeshInfo = srcMeshes[i]->GetMeshDS()->GetMeshInfo(); + for (int i = 0; i < SMDSEntity_Last; i++) + aVec[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i); + } + } + else + { + // std-like iterator used to get coordinates of nodes of mesh element + typedef SMDS_StdIterator< SMESH_MeshEditor::TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; + + SMESH_MesherHelper helper(theMesh); + helper.SetSubShape(theShape); + + const TopoDS_Face& geomFace = TopoDS::Face( theShape ); + const double faceTol = helper.MaxTolerance( geomFace ); + + // take into account nodes on vertices + TopExp_Explorer exp( theShape, TopAbs_VERTEX ); + for ( ; exp.More(); exp.Next() ) + theMesh.GetSubMesh( exp.Current())->Evaluate( aResMap ); + + // to count now many times a link between nodes encounters, + // negative nb additionally means that a link is quadratic + map linkCount; + map::iterator link2Nb; + + // count faces and nodes imported from groups + set allNodes; + gp_XY uv; + for ( int iG = 0; iG < srcGroups.size(); ++iG ) + { + const SMESHDS_GroupBase* srcGroup = srcGroups[iG]->GetGroupDS(); + SMDS_ElemIteratorPtr srcElems = srcGroup->GetElements(); + SMDS_MeshNode tmpNode(0,0,0); + while ( srcElems->more() ) // loop on group contents + { + const SMDS_MeshElement* face = srcElems->next(); + // find out if face is located on geomEdge by projecting + // a gravity center of face to geomFace + gp_XYZ gc(0,0,0); + gc = accumulate( TXyzIterator(face->nodesIterator()), TXyzIterator(), gc)/face->NbNodes(); + tmpNode.setXYZ( gc.X(), gc.Y(), gc.Z()); + if ( helper.CheckNodeUV( geomFace, &tmpNode, uv, 10 * faceTol, /*force=*/true )) + { + ++aVec[ face->GetEntityType() ]; + + // collect links + int nbConers = face->NbCornerNodes(); + for ( int i = 0; i < face->NbNodes(); ++i ) + { + const SMDS_MeshNode* n1 = face->GetNode(i); + allNodes.insert( n1 ); + if ( i < nbConers ) + { + const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbConers ); + link2Nb = linkCount.insert( make_pair( SMESH_TLink( n1, n2 ), 0)).first; + if ( (*link2Nb).second ) + link2Nb->second += (link2Nb->second < 0 ) ? -1 : 1; + else + link2Nb->second += ( face->IsQuadratic() ) ? -1 : 1; + } + } + } + } + } + + int nbNodes = allNodes.size(); + allNodes.clear(); + + // count nodes and edges on geom edges + + double u; + for ( exp.Init(theShape, TopAbs_EDGE); exp.More(); exp.Next() ) + { + TopoDS_Edge geomEdge = TopoDS::Edge( exp.Current() ); + SMESH_subMesh* sm = theMesh.GetSubMesh( geomEdge ); + vector& edgeVec = aResMap[sm]; + if ( edgeVec.empty() ) + { + edgeVec.resize(SMDSEntity_Last,0); + for ( link2Nb = linkCount.begin(); link2Nb != linkCount.end(); ) + { + const SMESH_TLink& link = (*link2Nb).first; + int nbFacesOfLink = Abs( link2Nb->second ); + bool eraseLink = ( nbFacesOfLink != 1 ); + if ( nbFacesOfLink == 1 ) + { + if ( helper.CheckNodeU( geomEdge, link.node1(), u, 10*faceTol, /*force=*/true )&& + helper.CheckNodeU( geomEdge, link.node2(), u, 10*faceTol, /*force=*/true )) + { + bool isQuadratic = ( link2Nb->second < 0 ); + ++edgeVec[ isQuadratic ? SMDSEntity_Quad_Edge : SMDSEntity_Edge ]; + ++edgeVec[ SMDSEntity_Node ]; + --nbNodes; + eraseLink = true; + } + } + if ( eraseLink ) + linkCount.erase(link2Nb++); + else + link2Nb++; + } + if ( edgeVec[ SMDSEntity_Node] > 0 ) + --edgeVec[ SMDSEntity_Node ]; // for one node on vertex + } + else if ( !helper.IsSeamShape( geomEdge ) || + geomEdge.Orientation() == TopAbs_FORWARD ) + { + nbNodes -= 1+edgeVec[ SMDSEntity_Node ]; + } + } + + aVec[SMDSEntity_Node] = nbNodes; + } + + SMESH_subMesh * sm = theMesh.GetSubMesh(theShape); + aResMap.insert(make_pair(sm,aVec)); + + return true; +} diff --git a/src/StdMeshers/StdMeshers_Import_1D2D.hxx b/src/StdMeshers/StdMeshers_Import_1D2D.hxx new file mode 100644 index 000000000..5733c2f48 --- /dev/null +++ b/src/StdMeshers/StdMeshers_Import_1D2D.hxx @@ -0,0 +1,60 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESH : implementaion of SMESH idl descriptions +// Module : SMESH +// +#ifndef _SMESH_Import_2D_HXX_ +#define _SMESH_Import_2D_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_2D_Algo.hxx" +#include "SMDS_MeshElement.hxx" + +class StdMeshers_ImportSource1D; + +/*! + * \brief Copy elements from other the mesh + */ +class STDMESHERS_EXPORT StdMeshers_Import_1D2D: public SMESH_2D_Algo +{ +public: + StdMeshers_Import_1D2D(int hypId, int studyId, SMESH_Gen* gen); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + virtual bool Compute (SMESH_Mesh & aMesh, const TopoDS_Shape & aShape); + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + + virtual void SetEventListener(SMESH_subMesh* subMesh); + virtual void SubmeshRestored(SMESH_subMesh* subMesh); + + private: + + StdMeshers_ImportSource1D* _sourceHyp; +}; + +#endif diff --git a/src/StdMeshers/StdMeshers_Penta_3D.cxx b/src/StdMeshers/StdMeshers_Penta_3D.cxx index bdab94ece..b9d46da9e 100644 --- a/src/StdMeshers/StdMeshers_Penta_3D.cxx +++ b/src/StdMeshers/StdMeshers_Penta_3D.cxx @@ -676,22 +676,16 @@ void StdMeshers_Penta_3D::MakeVolumeMesh() if ( aN.size() < nbFaceNodes * 2 ) aN.resize( nbFaceNodes * 2 ); // - k=0; - aItNodes=pE0->nodesIterator(); - while (aItNodes->more()) { - //const SMDS_MeshElement* pNode = aItNodes->next(); - const SMDS_MeshNode* pNode = - static_cast (aItNodes->next()); - if(myTool->IsMedium(pNode)) - continue; + for ( k=0; kGetNode(k); +// if(myTool->IsMedium(pNode)) +// continue; aID0 = pNode->GetID(); aJ[k] = GetIndexOnLayer(aID0); if (!myErrorStatus->IsOK()) { MESSAGE("StdMeshers_Penta_3D::MakeVolumeMesh"); return; } - // - ++k; } // bool forward = true; diff --git a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx index eaf669e58..38028c2d7 100644 --- a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx +++ b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx @@ -44,6 +44,7 @@ #include "utilities.h" +#include #include #include #include @@ -53,6 +54,8 @@ #include #include #include +#include +#include #include #include #include @@ -61,22 +64,22 @@ #include #include #include -#include -#include + +#include using namespace std; #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; } #define CONT_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); continue; } -#define SHOW_VERTEX(v,msg) \ +#define SHOW_SHAPE(v,msg) \ // { \ // if ( (v).IsNull() ) cout << msg << " NULL SHAPE" << endl; \ // else if ((v).ShapeType() == TopAbs_VERTEX) {\ // gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( (v) ));\ -// cout<()<<" ( "<()<ShapeToIndex(S), theMeshDS[1]->ShapeToIndex(S) ); + return long(S.TShape().operator->()); + } + //================================================================================ /*! * \brief Write shape for debug purposes @@ -116,31 +127,24 @@ namespace { */ //================================================================================ - void Reverse( list< TopoDS_Edge > & edges, const int nbEdges ) + void Reverse( list< TopoDS_Edge > & edges, const int nbEdges, const int firstEdge=0) { SHOW_LIST("BEFORE REVERSE", edges); list< TopoDS_Edge >::iterator eIt = edges.begin(); - if ( edges.size() == nbEdges ) - { - edges.reverse(); - } - else // reverse only the given nb of edges + std::advance( eIt, firstEdge ); + list< TopoDS_Edge >::iterator eBackIt = eIt; + for ( int i = 0; i < nbEdges; ++i, ++eBackIt ) + eBackIt->Reverse(); // reverse edge + // reverse list + --eBackIt; + while ( eIt != eBackIt ) { - // look for the last edge to be reversed - list< TopoDS_Edge >::iterator eBackIt = edges.begin(); - for ( int i = 1; i < nbEdges; ++i ) - ++eBackIt; - // reverse - while ( eIt != eBackIt ) { - std::swap( *eIt, *eBackIt ); - SHOW_LIST("# AFTER SWAP", edges) + std::swap( *eIt, *eBackIt ); + SHOW_LIST("# AFTER SWAP", edges) if ( (++eIt) != eBackIt ) --eBackIt; - } } - for ( eIt = edges.begin(); eIt != edges.end(); ++eIt ) - eIt->Reverse(); SHOW_LIST("ATFER REVERSE", edges) } @@ -351,6 +355,26 @@ namespace { return true; } + //================================================================================ + /*! + * \brief Return true if uv position of the vIndex-th vertex of edge on face is close + * enough to given uv + */ + //================================================================================ + + bool sameVertexUV( const TopoDS_Edge& edge, + const TopoDS_Face& face, + const int& vIndex, + const gp_Pnt2d& uv, + const double& tol2d ) + { + TopoDS_Vertex VV[2]; + TopExp::Vertices( edge, VV[0], VV[1], true); + gp_Pnt2d v1UV = BRep_Tool::Parameters( VV[vIndex], face); + double dist2d = v1UV.Distance( uv ); + return dist2d < tol2d; + } + } // namespace //======================================================================= @@ -381,7 +405,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // case TopAbs_EDGE: // case ...: // } - // else try to accosiate in different ways: + // 4) else try to accosiate in different ways: // a) accosiate shapes by propagation and other simple cases // switch ( ShapeType ) { // case TopAbs_EDGE: @@ -390,8 +414,11 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // b) find association of a couple of vertices and recall self. // + theMeshDS[0] = theMesh1->GetMeshDS(); // debug + theMeshDS[1] = theMesh2->GetMeshDS(); + // ================================================================================= - // Is it the case of associating a group member -> another group? (PAL16202, 16203) + // 1) Is it the case of associating a group member -> another group? (PAL16202, 16203) // ================================================================================= if ( theShape1.ShapeType() != theShape2.ShapeType() ) { TopoDS_Shape group1, group2; @@ -412,7 +439,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the bool bidirect = ( !theShape1.IsSame( theShape2 )); // ============ - // Is partner? + // 2) Is partner? // ============ bool partner = theShape1.IsPartner( theShape2 ); TopTools_DataMapIteratorOfDataMapOfShapeShape vvIt( theMap ); @@ -438,7 +465,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the if ( !theMap.IsEmpty() ) { //====================================================================== - // HAS initial vertex association + // 3) HAS initial vertex association //====================================================================== switch ( theShape1.ShapeType() ) { // ---------------------------------------------------------------------- @@ -448,6 +475,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the RETURN_BAD_RESULT("Wrong map extent " << theMap.Extent() ); TopoDS_Edge edge1 = TopoDS::Edge( theShape1 ); TopoDS_Edge edge2 = TopoDS::Edge( theShape2 ); + if ( edge1.Orientation() >= TopAbs_INTERNAL ) edge1.Orientation( TopAbs_FORWARD ); + if ( edge2.Orientation() >= TopAbs_INTERNAL ) edge2.Orientation( TopAbs_FORWARD ); TopoDS_Vertex VV1[2], VV2[2]; TopExp::Vertices( edge1, VV1[0], VV1[1] ); TopExp::Vertices( edge2, VV2[0], VV2[1] ); @@ -463,6 +492,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // ---------------------------------------------------------------------- TopoDS_Face face1 = TopoDS::Face( theShape1 ); TopoDS_Face face2 = TopoDS::Face( theShape2 ); + if ( face1.Orientation() >= TopAbs_INTERNAL ) face1.Orientation( TopAbs_FORWARD ); + if ( face2.Orientation() >= TopAbs_INTERNAL ) face2.Orientation( TopAbs_FORWARD ); TopoDS_Vertex VV1[2], VV2[2]; // find a not closed edge of face1 both vertices of which are associated @@ -510,6 +541,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopExp_Explorer exp ( theShape1, TopAbs_EDGE ); for ( ; VV2[ 1 ].IsNull() && exp.More(); exp.Next() ) { edge1 = TopoDS::Edge( exp.Current() ); + if ( edge1.Orientation() >= TopAbs_INTERNAL ) edge1.Orientation( TopAbs_FORWARD ); TopExp::Vertices( edge1 , VV1[0], VV1[1] ); if ( theMap.IsBound( VV1[0] )) { VV2[ 0 ] = TopoDS::Vertex( theMap( VV1[0] )); @@ -673,7 +705,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the if ( !initAssocOK ) { // for shell association there must be an edge with both vertices bound TopoDS_Vertex v1, v2; - TopExp::Vertices( TopoDS::Edge( it1.Value()), v1, v2 ); + TopExp::Vertices( TopoDS::Edge( it1.Value().Oriented(TopAbs_FORWARD)), v1, v2 ); initAssocOK = ( theMap.IsBound( v1 ) && theMap.IsBound( v2 )); } } @@ -876,7 +908,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } // end case of available initial vertex association //====================================================================== - // NO INITIAL VERTEX ASSOCIATION + // 4) NO INITIAL VERTEX ASSOCIATION //====================================================================== switch ( theShape1.ShapeType() ) { @@ -922,6 +954,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the { TopoDS_Face face1 = TopoDS::Face(theShape1); TopoDS_Face face2 = TopoDS::Face(theShape2); + if ( face1.Orientation() >= TopAbs_INTERNAL ) face1.Orientation( TopAbs_FORWARD ); + 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 )); @@ -1105,7 +1139,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the if ( edge.IsNull() || edge.ShapeType() != TopAbs_EDGE ) RETURN_BAD_RESULT("Edge not found"); - TopExp::Vertices( TopoDS::Edge( edge ), VV1[0], VV1[1]); + TopExp::Vertices( TopoDS::Edge( edge.Oriented(TopAbs_FORWARD)), VV1[0], VV1[1]); if ( VV1[0].IsSame( VV1[1] )) RETURN_BAD_RESULT("Only closed edges"); @@ -1161,19 +1195,23 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, list< TopoDS_Edge > & edges1, list< TopoDS_Edge > & edges2) { - list< int > nbVInW1, nbVInW2; - for ( int outer_wire_algo = 0; outer_wire_algo < 2; ++outer_wire_algo ) + bool OK = false; + list< int > nbEInW1, nbEInW2; + int i_ok_wire_algo = -1; + for ( int outer_wire_algo = 0; outer_wire_algo < 2 && !OK; ++outer_wire_algo ) { edges1.clear(); edges2.clear(); - if ( SMESH_Block::GetOrderedEdges( face1, VV1[0], edges1, nbVInW1, outer_wire_algo) != - SMESH_Block::GetOrderedEdges( face2, VV2[0], edges2, nbVInW2, outer_wire_algo) ) + if ( SMESH_Block::GetOrderedEdges( face1, VV1[0], edges1, nbEInW1, outer_wire_algo) != + SMESH_Block::GetOrderedEdges( face2, VV2[0], edges2, nbEInW2, outer_wire_algo) ) CONT_BAD_RESULT("Different number of wires in faces "); - if ( nbVInW1.front() != nbVInW2.front() ) + if ( nbEInW1 != nbEInW2 ) CONT_BAD_RESULT("Different number of edges in faces: " << - nbVInW1.front() << " != " << nbVInW2.front()); + nbEInW1.front() << " != " << nbEInW2.front()); + + i_ok_wire_algo = outer_wire_algo; // Define if we need to reverse one of wires to make edges in lists match each other @@ -1186,9 +1224,9 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, // check if the second vertex belongs to the first or last edge in the wire if ( !VV1[1].IsSame( TopExp::FirstVertex( *edgeIt, true ))) { bool KO = true; // belongs to none - if ( nbVInW1.size() > 1 ) { // several wires + if ( nbEInW1.size() > 1 ) { // several wires edgeIt = edges1.begin(); - for ( int i = 1; i < nbVInW1.front(); ++i ) ++edgeIt; + std::advance( edgeIt, nbEInW1.front()-1 ); KO = !VV1[1].IsSame( TopExp::FirstVertex( *edgeIt, true )); } if ( KO ) @@ -1201,9 +1239,9 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, // check if the second vertex belongs to the first or last edge in the wire if ( !VV2[1].IsSame( TopExp::FirstVertex( *edgeIt, true ))) { bool KO = true; // belongs to none - if ( nbVInW2.size() > 1 ) { // several wires + if ( nbEInW2.size() > 1 ) { // several wires edgeIt = edges2.begin(); - for ( int i = 1; i < nbVInW2.front(); ++i ) ++edgeIt; + std::advance( edgeIt, nbEInW2.front()-1 ); KO = !VV2[1].IsSame( TopExp::FirstVertex( *edgeIt, true )); } if ( KO ) @@ -1212,13 +1250,83 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, } if ( reverse ) { - Reverse( edges2 , nbVInW2.front()); + Reverse( edges2 , nbEInW2.front()); if (( VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) != ( VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true )))) CONT_BAD_RESULT("GetOrderedEdges() failed"); } + OK = true; + + } // loop algos getting an outer wire + + // Try to orient all (if !OK) or only internal wires (issue 0020996) by UV similarity + if (( !OK || nbEInW1.size() > 1 ) && i_ok_wire_algo > -1 ) + { + // Check that Vec(VV1[0],VV1[1]) in 2D on face1 is the same + // as Vec(VV2[0],VV2[1]) on face2 + double vTol = BRep_Tool::Tolerance( VV1[0] ); + BRepAdaptor_Surface surface1( face1, false ); + double vTolUV = + surface1.UResolution( vTol ) + surface1.VResolution( vTol ); // let's be tolerant + gp_Pnt2d v0f1UV = BRep_Tool::Parameters( VV1[0], face1 ); + gp_Pnt2d v0f2UV = BRep_Tool::Parameters( VV2[0], face2 ); + gp_Pnt2d v1f1UV = BRep_Tool::Parameters( VV1[1], face1 ); + gp_Pnt2d v1f2UV = BRep_Tool::Parameters( VV2[1], face2 ); + gp_Vec2d v01f1Vec( v0f1UV, v1f1UV ); + gp_Vec2d v01f2Vec( v0f2UV, v1f2UV ); + if ( Abs( v01f1Vec.X()-v01f2Vec.X()) < vTolUV && Abs( v01f1Vec.Y()-v01f2Vec.Y()) < vTolUV ) + { + if ( i_ok_wire_algo != 1 ) + { + 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); + } + gp_XY dUV = v0f2UV.XY() - v0f1UV.XY(); // UV shift between 2 faces + // skip edges of the outer wire (if the outer wire is OK) + list< int >::iterator nbEInW = nbEInW1.begin(); + list< TopoDS_Edge >::iterator edge1Beg = edges1.begin(), edge2Beg = edges2.begin(); + if ( OK ) + { + for ( int i = 0; i < *nbEInW; ++i ) + ++edge1Beg, ++edge2Beg; + ++nbEInW; + } + for ( ; nbEInW != nbEInW1.end(); ++nbEInW ) // loop on wires + { + // reach an end of edges of a current wire + list< TopoDS_Edge >::iterator edge1End = edge1Beg, edge2End = edge2Beg; + for ( int i = 0; i < *nbEInW; ++i ) + ++edge1End, ++edge2End; + // rotate edges2 untill coincident with edges1 in 2D + v0f1UV = BRep_Tool::Parameters( TopExp::FirstVertex(*edge1Beg,true), face1 ); + v1f1UV = BRep_Tool::Parameters( TopExp::LastVertex (*edge1Beg,true), face1 ); + v0f1UV.ChangeCoord() += dUV; + v1f1UV.ChangeCoord() += dUV; + int i = *nbEInW; + while ( --i > 0 && !sameVertexUV( *edge2Beg, face2, 0, v0f1UV, vTolUV )) + edges2.splice( edge2End, edges2, edge2Beg++ ); // move edge2Beg to place before edge2End + if ( sameVertexUV( *edge2Beg, face2, 0, v0f1UV, vTolUV )) + { + if ( nbEInW == nbEInW1.begin() ) + OK = true; // OK is for the first wire + // reverse edges2 if needed + if ( !sameVertexUV( *edge2Beg, face2, 1, v1f1UV, vTolUV )) + { + Reverse( edges2 , *nbEInW, distance( edges2.begin(),edge2Beg )); + // set correct edge2End + edge2End = edges2.begin(); + std::advance( edge2End, std::accumulate( nbEInW1.begin(), nbEInW, *nbEInW)); + } + } + // prepare to the next wire loop + edge1Beg = edge1End, edge2Beg = edge2End; + } + } } - return nbVInW2.front(); + + return OK ? nbEInW1.front() : 0; } //======================================================================= @@ -1271,8 +1379,8 @@ bool StdMeshers_ProjectionUtils::InsertAssociation( const TopoDS_Shape& theShape const bool theBidirectional) { if ( !theShape1.IsNull() && !theShape2.IsNull() ) { - SHOW_VERTEX(theShape1,"Assoc "); - SHOW_VERTEX(theShape2," to "); + SHOW_SHAPE(theShape1,"Assoc "); + SHOW_SHAPE(theShape2," to "); bool isNew = ( theAssociationMap.Bind( theShape1, theShape2 )); if ( theBidirectional ) theAssociationMap.Bind( theShape2, theShape1 ); diff --git a/src/StdMeshers/StdMeshers_Propagation.cxx b/src/StdMeshers/StdMeshers_Propagation.cxx index 8b88ce99a..481803839 100644 --- a/src/StdMeshers/StdMeshers_Propagation.cxx +++ b/src/StdMeshers/StdMeshers_Propagation.cxx @@ -30,6 +30,7 @@ #include "SMDS_SetIterator.hxx" #include "SMESH_Algo.hxx" +#include "SMESH_Gen.hxx" #include "SMESH_HypoFilter.hxx" #include "SMESH_Mesh.hxx" #include "SMESH_subMesh.hxx" @@ -40,7 +41,7 @@ #include #define DBGMSG(txt) \ -// cout << txt << endl; + // cout << txt << endl; using namespace std; @@ -347,6 +348,10 @@ namespace { oppSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); oppData->SetState( IN_CHAIN ); DBGMSG( "set IN_CHAIN on " << oppSM->GetId() ); + if ( oppSM->GetAlgoState() != SMESH_subMesh::HYP_OK ) + // make oppSM check algo state + if ( SMESH_Algo* algo = mesh->GetGen()->GetAlgo( *mesh, anOppE )) + oppSM->AlgoStateEngine(SMESH_subMesh::ADD_FATHER_ALGO,algo); } else { oppData->SetState( LAST_IN_CHAIN ); @@ -455,6 +460,7 @@ namespace { void PropagationMgr::Set(SMESH_subMesh * submesh) { + if ( findData( submesh )) return; DBGMSG( "PropagationMgr::Set() on " << submesh->GetId() ); EventListenerData* data = new PropagationMgrData(); submesh->SetEventListener( getListener(), data, submesh ); diff --git a/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.cxx b/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.cxx index 1ca7e5b12..8e2718dd0 100644 --- a/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.cxx +++ b/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.cxx @@ -25,8 +25,10 @@ // #include "StdMeshers_QuadToTriaAdaptor.hxx" -#include -#include +#include "SMDS_SetIterator.hxx" + +#include "SMESH_Algo.hxx" +#include "SMESH_MesherHelper.hxx" #include #include @@ -44,9 +46,297 @@ using namespace std; enum EQuadNature { NOT_QUAD, QUAD, DEGEN_QUAD }; - // sdt-like iterator used to get coordinates of nodes of mesh element +// std-like iterator used to get coordinates of nodes of mesh element typedef SMDS_StdIterator< SMESH_MeshEditor::TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; +namespace +{ + const int Q2TAbs_TmpTriangle = SMDSEntity_Last + 1; + + //================================================================================ + /*! + * \brief Temporary face. It's key feature is that it adds itself to an apex node + * as inverse element, so that tmp triangles of a piramid can be easily found + */ + //================================================================================ + + class STDMESHERS_EXPORT Q2TAdaptor_Triangle : public SMDS_MeshFace + { + const SMDS_MeshNode* _nodes[3]; + public: + Q2TAdaptor_Triangle(const SMDS_MeshNode* apexNode, + const SMDS_MeshNode* node2, + const SMDS_MeshNode* node3) + { + _nodes[0]=0; ChangeApex(apexNode); + _nodes[1]=node2; + _nodes[2]=node3; + } + ~Q2TAdaptor_Triangle() { MarkAsRemoved(); } + void ChangeApex(const SMDS_MeshNode* node) + { + MarkAsRemoved(); + _nodes[0]=node; + const_cast(node)->AddInverseElement(this); + } + void MarkAsRemoved() + { + if ( _nodes[0] ) + const_cast(_nodes[0])->RemoveInverseElement(this), _nodes[0] = 0; + } + bool IsRemoved() const { return !_nodes[0]; } + virtual int NbNodes() const { return 3; } + virtual const SMDS_MeshNode* GetNode(const int ind) const { return _nodes[ind]; } + virtual SMDSAbs_EntityType GetEntityType() const + { + return SMDSAbs_EntityType( Q2TAbs_TmpTriangle ); + } + virtual SMDS_ElemIteratorPtr elementsIterator(SMDSAbs_ElementType type) const + { + if ( type == SMDSAbs_Node ) + return SMDS_ElemIteratorPtr( new SMDS_NodeArrayElemIterator( _nodes, _nodes+3 )); + throw SALOME_Exception(LOCALIZED("Not implemented")); + } + }; + + //================================================================================ + /*! + * \brief Return true if two nodes of triangles are equal + */ + //================================================================================ + + bool EqualTriangles(const SMDS_MeshElement* F1,const SMDS_MeshElement* F2) + { + return + ( F1->GetNode(1)==F2->GetNode(2) && F1->GetNode(2)==F2->GetNode(1) ) || + ( F1->GetNode(1)==F2->GetNode(1) && F1->GetNode(2)==F2->GetNode(2) ); + } + + //================================================================================ + /*! + * \brief Merge the two pyramids (i.e. fuse their apex) and others already merged with them + */ + //================================================================================ + + void MergePiramids( const SMDS_MeshElement* PrmI, + const SMDS_MeshElement* PrmJ, + SMESHDS_Mesh* meshDS, + set & nodesToMove) + { + const SMDS_MeshNode* Nrem = PrmJ->GetNode(4); // node to remove + int nbJ = Nrem->NbInverseElements( SMDSAbs_Volume ); + SMESH_MeshEditor::TNodeXYZ Pj( Nrem ); + + // an apex node to make common to all merged pyramids + SMDS_MeshNode* CommonNode = const_cast(PrmI->GetNode(4)); + if ( CommonNode == Nrem ) return; // already merged + int nbI = CommonNode->NbInverseElements( SMDSAbs_Volume ); + SMESH_MeshEditor::TNodeXYZ Pi( CommonNode ); + gp_XYZ Pnew = ( nbI*Pi + nbJ*Pj ) / (nbI+nbJ); + CommonNode->setXYZ( Pnew.X(), Pnew.Y(), Pnew.Z() ); + + nodesToMove.insert( CommonNode ); + nodesToMove.erase ( Nrem ); + + // find and remove coincided faces of merged pyramids + SMDS_ElemIteratorPtr triItI = CommonNode->GetInverseElementIterator(SMDSAbs_Face); + while ( triItI->more() ) + { + const SMDS_MeshElement* FI = triItI->next(); + const SMDS_MeshElement* FJEqual = 0; + SMDS_ElemIteratorPtr triItJ = Nrem->GetInverseElementIterator(SMDSAbs_Face); + while ( !FJEqual && triItJ->more() ) + { + const SMDS_MeshElement* FJ = triItJ->next(); + if ( EqualTriangles( FJ, FI )) + FJEqual = FJ; + } + if ( FJEqual ) + { + ((Q2TAdaptor_Triangle*) FI)->MarkAsRemoved(); + ((Q2TAdaptor_Triangle*) FJEqual)->MarkAsRemoved(); + } + } + + // set the common apex node to pyramids and triangles merged with J + SMDS_ElemIteratorPtr itJ = Nrem->GetInverseElementIterator(); + while ( itJ->more() ) + { + const SMDS_MeshElement* elem = itJ->next(); + if ( elem->GetType() == SMDSAbs_Volume ) // pyramid + { + vector< const SMDS_MeshNode* > nodes( elem->begin_nodes(), elem->end_nodes() ); + nodes[4] = CommonNode; + meshDS->ChangeElementNodes( elem, &nodes[0], nodes.size()); + } + else if ( elem->GetEntityType() == Q2TAbs_TmpTriangle ) // tmp triangle + { + ((Q2TAdaptor_Triangle*) elem )->ChangeApex( CommonNode ); + } + } + ASSERT( Nrem->NbInverseElements() == 0 ); + meshDS->RemoveFreeNode( Nrem, + meshDS->MeshElements( Nrem->GetPosition()->GetShapeId()), + /*fromGroups=*/false); + } + + //================================================================================ + /*! + * \brief Return true if two adjacent pyramids are too close one to another + * so that a tetrahedron to built between them would have too poor quality + */ + //================================================================================ + + bool TooCloseAdjacent( const SMDS_MeshElement* PrmI, + const SMDS_MeshElement* PrmJ, + const bool hasShape) + { + const SMDS_MeshNode* nApexI = PrmI->GetNode(4); + const SMDS_MeshNode* nApexJ = PrmJ->GetNode(4); + if ( nApexI == nApexJ || + nApexI->GetPosition()->GetShapeId() != nApexJ->GetPosition()->GetShapeId() ) + return false; + + // Find two common base nodes and their indices within PrmI and PrmJ + const SMDS_MeshNode* baseNodes[2] = { 0,0 }; + int baseNodesIndI[2], baseNodesIndJ[2]; + for ( int i = 0; i < 4 ; ++i ) + { + int j = PrmJ->GetNodeIndex( PrmI->GetNode(i)); + if ( j >= 0 ) + { + int ind = baseNodes[0] ? 1:0; + if ( baseNodes[ ind ]) + return false; // pyramids with a common base face + baseNodes [ ind ] = PrmI->GetNode(i); + baseNodesIndI[ ind ] = i; + baseNodesIndJ[ ind ] = j; + } + } + if ( !baseNodes[1] ) return false; // not adjacent + + // Get normals of triangles sharing baseNodes + gp_XYZ apexI = SMESH_MeshEditor::TNodeXYZ( nApexI ); + gp_XYZ apexJ = SMESH_MeshEditor::TNodeXYZ( nApexJ ); + gp_XYZ base1 = SMESH_MeshEditor::TNodeXYZ( baseNodes[0]); + gp_XYZ base2 = SMESH_MeshEditor::TNodeXYZ( baseNodes[1]); + gp_Vec baseVec( base1, base2 ); + gp_Vec baI( base1, apexI ); + gp_Vec baJ( base1, apexJ ); + gp_Vec nI = baseVec.Crossed( baI ); + gp_Vec nJ = baseVec.Crossed( baJ ); + + // Check angle between normals + double angle = nI.Angle( nJ ); + bool tooClose = ( angle < 15 * PI180 ); + + // Check if pyramids collide + bool isOutI, isOutJ; + if ( !tooClose && baI * baJ > 0 ) + { + // find out if nI points outside of PrmI or inside + int dInd = baseNodesIndI[1] - baseNodesIndI[0]; + isOutI = ( abs(dInd)==1 ) ? dInd < 0 : dInd > 0; + + // find out sign of projection of nJ to baI + double proj = baI * nJ; + + tooClose = isOutI ? proj > 0 : proj < 0; + } + + // Check if PrmI and PrmJ are in same domain + if ( tooClose && !hasShape ) + { + // check order of baseNodes within pyramids, it must be opposite + int dInd = baseNodesIndJ[1] - baseNodesIndJ[0]; + isOutJ = ( abs(dInd)==1 ) ? dInd < 0 : dInd > 0; + if ( isOutJ == isOutI ) + return false; // other domain + + // check absence of a face separating domains between pyramids + TIDSortedElemSet emptySet, avoidSet; + int i1, i2; + while ( const SMDS_MeshElement* f = + SMESH_MeshEditor::FindFaceInSet( baseNodes[0], baseNodes[1], + emptySet, avoidSet, &i1, &i2 )) + { + avoidSet.insert( f ); + + // face node other than baseNodes + int otherNodeInd = 0; + while ( otherNodeInd == i1 || otherNodeInd == i2 ) otherNodeInd++; + const SMDS_MeshNode* otherFaceNode = f->GetNode( otherNodeInd ); + + // check if f is a base face of either of pyramids + if ( f->NbCornerNodes() == 4 && + ( PrmI->GetNodeIndex( otherFaceNode ) >= 0 || + PrmJ->GetNodeIndex( otherFaceNode ) >= 0 )) + continue; // f is a base quadrangle + + // check projections of face direction (baOFN) to triange normals (nI and nJ) + gp_Vec baOFN( base1, SMESH_MeshEditor::TNodeXYZ( otherFaceNode )); + ( isOutI ? nJ : nI ).Reverse(); + if ( nI * baOFN > 0 && nJ * baOFN > 0 ) + { + tooClose = false; // f is between pyramids + break; + } + } + } + + return tooClose; + } + + //================================================================================ + /*! + * \brief Merges adjacent pyramids + */ + //================================================================================ + + void MergeAdjacent(const SMDS_MeshElement* PrmI, + SMESH_Mesh& mesh, + set& nodesToMove) + { + TIDSortedElemSet adjacentPyrams, mergedPyrams; + for(int k=0; k<4; k++) // loop on 4 base nodes of PrmI + { + const SMDS_MeshNode* n = PrmI->GetNode(k); + SMDS_ElemIteratorPtr vIt = n->GetInverseElementIterator( SMDSAbs_Volume ); + while ( vIt->more() ) + { + const SMDS_MeshElement* PrmJ = vIt->next(); + if ( PrmJ->NbCornerNodes() != 5 || !adjacentPyrams.insert( PrmJ ).second ) + continue; + if ( PrmI != PrmJ && TooCloseAdjacent( PrmI, PrmJ, mesh.HasShapeToMesh() )) + { + MergePiramids( PrmI, PrmJ, mesh.GetMeshDS(), nodesToMove ); + mergedPyrams.insert( PrmJ ); + } + } + } + if ( !mergedPyrams.empty() ) + { + TIDSortedElemSet::iterator prm; +// for (prm = mergedPyrams.begin(); prm != mergedPyrams.end(); ++prm) +// MergeAdjacent( *prm, mesh, nodesToMove ); + + for (prm = adjacentPyrams.begin(); prm != adjacentPyrams.end(); ++prm) + MergeAdjacent( *prm, mesh, nodesToMove ); + } + } +} + +//================================================================================ +/*! + * \brief Constructor + */ +//================================================================================ + +StdMeshers_QuadToTriaAdaptor::StdMeshers_QuadToTriaAdaptor(): + myElemSearcher(0), myNbTriangles(0) +{ +} + //================================================================================ /*! * \brief Destructor @@ -66,9 +356,8 @@ StdMeshers_QuadToTriaAdaptor::~StdMeshers_QuadToTriaAdaptor() } myResMap.clear(); -// TF2PyramMap::iterator itp = myPyram2Trias.begin(); -// for(; itp!=myPyram2Trias.end(); itp++) -// cout << itp->second << endl; + if ( myElemSearcher ) delete myElemSearcher; + myElemSearcher=0; } @@ -120,7 +409,7 @@ static bool HasIntersection3(const gp_Pnt& P, const gp_Pnt& PC, gp_Pnt& Pint, return false; if( IAICQ.NbPoints() == 1 ) { gp_Pnt PIn = IAICQ.Point(1); - double preci = 1.e-6; + const double preci = 1.e-10 * P.Distance(PC); // check if this point is internal for segment [PC,P] bool IsExternal = ( (PC.X()-PIn.X())*(P.X()-PIn.X()) > preci ) || @@ -133,32 +422,34 @@ static bool HasIntersection3(const gp_Pnt& P, const gp_Pnt& PC, gp_Pnt& Pint, gp_Vec V1(PIn,P1); gp_Vec V2(PIn,P2); gp_Vec V3(PIn,P3); - if( V1.Magnitude()(myElemSearcher); + + //SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); //cout<<" CheckIntersection: meshDS->NbFaces() = "<NbFaces()<MeshElements(aShapeFace); - if ( aSubMeshDSFace ) { - SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements(); - while ( iteratorElem->more() ) { // loop on elements on a face - const SMDS_MeshElement* face = iteratorElem->next(); - Handle(TColgp_HSequenceOfPnt) aContour = new TColgp_HSequenceOfPnt; - SMDS_ElemIteratorPtr nodeIt = face->nodesIterator(); - int nbN = face->NbNodes(); - if( face->IsQuadratic() ) - nbN /= 2; - for ( int i = 0; i < nbN; ++i ) { - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - aContour->Append(gp_Pnt(node->X(), node->Y(), node->Z())); - } - if( HasIntersection(P, PC, Pres, aContour) ) { - res = true; - double tmp = PC.Distance(Pres); - if(tmp suspectElems; + searcher->GetElementsNearLine( line, SMDSAbs_Face, suspectElems); + +// for (TopExp_Explorer exp(aShape,TopAbs_FACE);exp.More();exp.Next()) { +// const TopoDS_Shape& aShapeFace = exp.Current(); +// if(aShapeFace==NotCheckedFace) +// continue; +// const SMESHDS_SubMesh * aSubMeshDSFace = meshDS->MeshElements(aShapeFace); +// if ( aSubMeshDSFace ) { +// SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements(); +// while ( iteratorElem->more() ) { // loop on elements on a face +// const SMDS_MeshElement* face = iteratorElem->next(); + for ( int i = 0; i < suspectElems.size(); ++i ) + { + const SMDS_MeshElement* face = suspectElems[i]; + if ( face == NotCheckedFace ) continue; + Handle(TColgp_HSequenceOfPnt) aContour = new TColgp_HSequenceOfPnt; + for ( int i = 0; i < face->NbCornerNodes(); ++i ) + aContour->Append( SMESH_MeshEditor::TNodeXYZ( face->GetNode(i) )); + if( HasIntersection(P, PC, Pres, aContour) ) { + res = true; + double tmp = PC.Distance(Pres); + if(tmpGetNode(1)==F2->GetNode(2) && F1->GetNode(2)==F2->GetNode(1) ) || - ( F1->GetNode(1)==F2->GetNode(1) && F1->GetNode(2)==F2->GetNode(2) ); -} - //================================================================================ /*! * \brief Prepare data for the given face @@ -288,9 +580,11 @@ int StdMeshers_QuadToTriaAdaptor::Preparation(const SMDS_MeshElement* face gp_Vec& VNorm, const SMDS_MeshElement** volumes) { - if( face->NbNodes() != ( face->IsQuadratic() ? 8 : 4 )) - if( face->NbNodes() != 4 ) - return NOT_QUAD; + if( face->NbCornerNodes() != 4 ) + { + myNbTriangles += int( face->NbCornerNodes() == 3 ); + return NOT_QUAD; + } int i = 0; gp_XYZ xyzC(0., 0., 0.); @@ -403,21 +697,26 @@ int StdMeshers_QuadToTriaAdaptor::Preparation(const SMDS_MeshElement* face bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { myResMap.clear(); - myPyram2Trias.clear(); + myPyramids.clear(); + myNbTriangles = 0; + myShape = aShape; SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); SMESH_MesherHelper helper(aMesh); helper.IsQuadraticSubMesh(aShape); helper.SetElementsOnShape( true ); - for (TopExp_Explorer exp(aShape,TopAbs_FACE);exp.More();exp.Next()) { + for (TopExp_Explorer exp(aShape,TopAbs_FACE);exp.More();exp.Next()) + { const TopoDS_Shape& aShapeFace = exp.Current(); const SMESHDS_SubMesh * aSubMeshDSFace = meshDS->MeshElements( aShapeFace ); - if ( aSubMeshDSFace ) { + if ( aSubMeshDSFace ) + { bool isRev = SMESH_Algo::IsReversedSubMesh( TopoDS::Face(aShapeFace), meshDS ); SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements(); - while ( iteratorElem->more() ) { // loop on elements on a face + while ( iteratorElem->more() ) // loop on elements on a geometrical face + { const SMDS_MeshElement* face = iteratorElem->next(); //cout<GetID() = "<GetID()<second; for(i=0; i<4; i++) - triaList.push_back( new SMDS_FaceOfNodes( NewNode, FNodes[i], FNodes[i+1] )); + triaList.push_back( new Q2TAdaptor_Triangle( NewNode, FNodes[i], FNodes[i+1] )); - // create pyramid + // create a pyramid if ( isRev ) swap( FNodes[1], FNodes[3]); SMDS_MeshVolume* aPyram = helper.AddVolume( FNodes[0], FNodes[1], FNodes[2], FNodes[3], NewNode ); - myPyram2Trias.insert(make_pair(aPyram, & triaList)); + myPyramids.push_back(aPyram); + } // end loop on elements on a face submesh } } // end for(TopExp_Explorer exp(aShape,TopAbs_FACE);exp.More();exp.Next()) { @@ -508,30 +809,30 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape return Compute2ndPart(aMesh); } - -//======================================================================= -//function : Compute -//purpose : -//======================================================================= +//================================================================================ +/*! + * \brief Computes pyramids in mesh with no shape + */ +//================================================================================ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh) { myResMap.clear(); - myPyram2Trias.clear(); + myPyramids.clear(); SMESH_MesherHelper helper(aMesh); helper.IsQuadraticSubMesh(aMesh.GetShapeToMesh()); helper.SetElementsOnShape( true ); - SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); + if ( !myElemSearcher ) + myElemSearcher = SMESH_MeshEditor(&aMesh).GetElementSearcher(); + SMESH_ElementSearcher* searcher = const_cast(myElemSearcher); - SMDS_FaceIteratorPtr fIt = meshDS->facesIterator(); - TIDSortedElemSet sortedFaces; // 0020279: control the "random" use when using mesh algorithms - while( fIt->more()) sortedFaces.insert( fIt->next() ); + SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); - TIDSortedElemSet::iterator itFace = sortedFaces.begin(), fEnd = sortedFaces.end(); - for ( ; itFace != fEnd; ++itFace ) + SMDS_FaceIteratorPtr fIt = meshDS->facesIterator(/*idInceasingOrder=*/true); + while( fIt->more()) { - const SMDS_MeshElement* face = *itFace; + const SMDS_MeshElement* face = fIt->next(); if ( !face ) continue; //cout<GetID() = "<GetID()<Value(1).Distance(PN->Value(2)) + PN->Value(2).Distance(PN->Value(3)); @@ -566,8 +867,13 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh) double dist1 = RealLast(); double dist2 = RealLast(); gp_Pnt Pres1,Pres2; - for (TIDSortedElemSet::iterator itF = sortedFaces.begin(); itF != fEnd; ++itF ) { - const SMDS_MeshElement* F = *itF; + + gp_Ax1 line( PC, VNorm ); + vector< const SMDS_MeshElement* > suspectElems; + searcher->GetElementsNearLine( line, SMDSAbs_Face, suspectElems); + + for ( int iF = 0; iF < suspectElems.size(); ++iF ) { + const SMDS_MeshElement* F = suspectElems[iF]; if(F==face) continue; Handle(TColgp_HSequenceOfPnt) aContour = new TColgp_HSequenceOfPnt; for ( int i = 0; i < 4; ++i ) @@ -610,9 +916,9 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh) } } if(!IsRev) - NewFace = new SMDS_FaceOfNodes( FNodes[0], FNodes[1], FNodes[2] ); + NewFace = new Q2TAdaptor_Triangle( FNodes[0], FNodes[1], FNodes[2] ); else - NewFace = new SMDS_FaceOfNodes( FNodes[0], FNodes[2], FNodes[1] ); + NewFace = new Q2TAdaptor_Triangle( FNodes[0], FNodes[2], FNodes[1] ); aList.push_back(NewFace); myResMap.insert(make_pair(face,aList)); continue; @@ -646,9 +952,14 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh) bool intersected[2] = { false, false }; double dist [2] = { RealLast(), RealLast() }; gp_Pnt intPnt[2]; - for (TIDSortedElemSet::iterator itF = sortedFaces.begin(); itF != fEnd; ++itF ) + + gp_Ax1 line( PC, tmpDir ); + vector< const SMDS_MeshElement* > suspectElems; + searcher->GetElementsNearLine( line, SMDSAbs_Face, suspectElems); + + for ( int iF = 0; iF < suspectElems.size(); ++iF ) { - const SMDS_MeshElement* F = *itF; + const SMDS_MeshElement* F = suspectElems[iF]; if(F==face) continue; Handle(TColgp_HSequenceOfPnt) aContour = new TColgp_HSequenceOfPnt; int nbN = F->NbNodes() / ( F->IsQuadratic() ? 2 : 1 ); @@ -683,11 +994,11 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh) // add triangles to result map TTriaList& aList = myResMap.insert( make_pair( face, TTriaList()))->second; for(i=0; i<4; i++) { - SMDS_FaceOfNodes* NewFace; + SMDS_MeshFace* NewFace; if(isRev) - NewFace = new SMDS_FaceOfNodes( NewNode, FNodes[i], FNodes[i+1] ); + NewFace = new Q2TAdaptor_Triangle( NewNode, FNodes[i], FNodes[i+1] ); else - NewFace = new SMDS_FaceOfNodes( NewNode, FNodes[i+1], FNodes[i] ); + NewFace = new Q2TAdaptor_Triangle( NewNode, FNodes[i+1], FNodes[i] ); aList.push_back(NewFace); } // create a pyramid @@ -696,231 +1007,162 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh) aPyram = helper.AddVolume( FNodes[0], FNodes[1], FNodes[2], FNodes[3], NewNode ); else aPyram = helper.AddVolume( FNodes[0], FNodes[3], FNodes[2], FNodes[1], NewNode ); - myPyram2Trias.insert(make_pair(aPyram, & aList)); + myPyramids.push_back(aPyram); } } // end loop on all faces return Compute2ndPart(aMesh); } -//======================================================================= -//function : Compute2ndPart -//purpose : Update created pyramids and faces to avoid their intersection -//======================================================================= +//================================================================================ +/*! + * \brief Update created pyramids and faces to avoid their intersection + */ +//================================================================================ bool StdMeshers_QuadToTriaAdaptor::Compute2ndPart(SMESH_Mesh& aMesh) { + if(myPyramids.empty()) + return true; + SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); + int i, j, k, myShapeID = myPyramids[0]->GetNode(4)->GetPosition()->GetShapeId(); - // check intersections between created pyramids + if ( !myElemSearcher ) + myElemSearcher = SMESH_MeshEditor(&aMesh).GetElementSearcher(); + SMESH_ElementSearcher* searcher = const_cast(myElemSearcher); - if(myPyram2Trias.empty()) - return true; + set nodesToMove; - int k = 0; + // check adjacent pyramids - // for each pyramid store list of merged pyramids with their faces - typedef map< const SMDS_MeshElement*, list< TPyram2Trias::iterator > > TPyram2Merged; - TPyram2Merged MergesInfo; + for ( i = 0; i < myPyramids.size(); ++i ) + { + const SMDS_MeshElement* PrmI = myPyramids[i]; + MergeAdjacent( PrmI, aMesh, nodesToMove ); + } // iterate on all pyramids - TPyram2Trias::iterator itPi = myPyram2Trias.begin(), itPEnd = myPyram2Trias.end(); - for ( ; itPi != itPEnd; ++itPi ) + for ( i = 0; i < myPyramids.size(); ++i ) { - const SMDS_MeshElement* PrmI = itPi->first; - TPyram2Merged::iterator pMergesI = MergesInfo.find( PrmI ); - - TXyzIterator xyzIt( PrmI->nodesIterator() ); - vector PsI( xyzIt, TXyzIterator() ); + const SMDS_MeshElement* PrmI = myPyramids[i]; // compare PrmI with all the rest pyramids - bool NeedMove = false; - TPyram2Trias::iterator itPj = itPi; - for ( ++itPj; itPj != itPEnd; ++itPj ) + + // collect adjacent pyramids and nodes coordinates of PrmI + set checkedPyrams; + vector PsI(5); + for(k=0; k<5; k++) // loop on 4 base nodes of PrmI + { + const SMDS_MeshNode* n = PrmI->GetNode(k); + PsI[k] = SMESH_MeshEditor::TNodeXYZ( n ); + SMDS_ElemIteratorPtr vIt = n->GetInverseElementIterator( SMDSAbs_Volume ); + while ( vIt->more() ) + checkedPyrams.insert( vIt->next() ); + } + + // check intersection with distant pyramids + for(k=0; k<4; k++) // loop on 4 base nodes of PrmI { - const SMDS_MeshElement* PrmJ = itPj->first; - TPyram2Merged::iterator pMergesJ = MergesInfo.find( PrmJ ); - - // check if two pyramids already merged - if ( pMergesJ != MergesInfo.end() && - find(pMergesJ->second.begin(),pMergesJ->second.end(), itPi )!=pMergesJ->second.end()) - continue; // already merged - - xyzIt = TXyzIterator( PrmJ->nodesIterator() ); - vector PsJ( xyzIt, TXyzIterator() ); - - bool hasInt = false; - gp_Pnt Pint; - for(k=0; k<4 && !hasInt; k++) { - gp_Vec Vtmp(PsI[k],PsI[4]); - gp_Pnt Pshift = PsI[k].XYZ() + Vtmp.XYZ() * 0.01; - hasInt = + gp_Vec Vtmp(PsI[k],PsI[4]); + gp_Pnt Pshift = PsI[k].XYZ() + Vtmp.XYZ() * 0.01; // base node moved a bit to apex + + gp_Ax1 line( PsI[k], Vtmp ); + vector< const SMDS_MeshElement* > suspectPyrams; + searcher->GetElementsNearLine( line, SMDSAbs_Volume, suspectPyrams); + + for ( j = 0; j < suspectPyrams.size(); ++j ) + { + const SMDS_MeshElement* PrmJ = suspectPyrams[j]; + if ( PrmJ == PrmI || PrmJ->NbCornerNodes() != 5 ) + continue; + if ( myShapeID != PrmJ->GetNode(4)->GetPosition()->GetShapeId()) + continue; // pyramid from other SOLID + if ( PrmI->GetNode(4) == PrmJ->GetNode(4) ) + continue; // pyramids PrmI and PrmJ already merged + if ( !checkedPyrams.insert( PrmJ ).second ) + continue; // already checked + + TXyzIterator xyzIt( PrmJ->nodesIterator() ); + vector PsJ( xyzIt, TXyzIterator() ); + + gp_Pnt Pint; + bool hasInt = ( HasIntersection3( Pshift, PsI[4], Pint, PsJ[0], PsJ[1], PsJ[4]) || HasIntersection3( Pshift, PsI[4], Pint, PsJ[1], PsJ[2], PsJ[4]) || HasIntersection3( Pshift, PsI[4], Pint, PsJ[2], PsJ[3], PsJ[4]) || HasIntersection3( Pshift, PsI[4], Pint, PsJ[3], PsJ[0], PsJ[4]) ); - } - for(k=0; k<4 && !hasInt; k++) { - gp_Vec Vtmp(PsJ[k],PsJ[4]); - gp_Pnt Pshift = PsJ[k].XYZ() + Vtmp.XYZ() * 0.01; - hasInt = - ( HasIntersection3( Pshift, PsJ[4], Pint, PsI[0], PsI[1], PsI[4]) || - HasIntersection3( Pshift, PsJ[4], Pint, PsI[1], PsI[2], PsI[4]) || - HasIntersection3( Pshift, PsJ[4], Pint, PsI[2], PsI[3], PsI[4]) || - HasIntersection3( Pshift, PsJ[4], Pint, PsI[3], PsI[0], PsI[4]) ); - } - if(hasInt) { - // count common nodes of base faces of two pyramids - int nbc = 0; - for(k=0; k<4; k++) - nbc += int ( PrmI->GetNodeIndex( PrmJ->GetNode(k) ) >= 0 ); - //cout<<" nbc = "<0) + if ( hasInt ) { - // Merge the two pyramids and others already merged with them + // count common nodes of base faces of two pyramids + int nbc = 0; + for (k=0; k<4; k++) + nbc += int ( PrmI->GetNodeIndex( PrmJ->GetNode(k) ) >= 0 ); - // initialize merge info of pyramids - if ( pMergesI == MergesInfo.end() ) // first merge of PrmI - { - pMergesI = MergesInfo.insert( make_pair( PrmI, list())).first; - pMergesI->second.push_back( itPi ); - } - if ( pMergesJ == MergesInfo.end() ) // first merge of PrmJ - { - pMergesJ = MergesInfo.insert( make_pair( PrmJ, list())).first; - pMergesJ->second.push_back( itPj ); - } - int nbI = pMergesI->second.size(), nbJ = pMergesJ->second.size(); - - // an apex node to make common to all merged pyramids - SMDS_MeshNode* CommonNode = const_cast(PrmI->GetNode(4)); - CommonNode->setXYZ( ( nbI*PsI[4].X() + nbJ*PsJ[4].X() ) / (nbI+nbJ), - ( nbI*PsI[4].Y() + nbJ*PsJ[4].Y() ) / (nbI+nbJ), - ( nbI*PsI[4].Z() + nbJ*PsJ[4].Z() ) / (nbI+nbJ) ); - NeedMove = true; - const SMDS_MeshNode* Nrem = PrmJ->GetNode(4); // node to remove - - list< TPyram2Trias::iterator >& aMergesI = pMergesI->second; - list< TPyram2Trias::iterator >& aMergesJ = pMergesJ->second; - - // find and remove coincided faces of merged pyramids - list< TPyram2Trias::iterator >::iterator itPttI, itPttJ; - TTriaList::iterator trI, trJ; - for ( itPttI = aMergesI.begin(); itPttI != aMergesI.end(); ++itPttI ) + if ( nbc == 4 ) + continue; // pyrams have a common base face + + if(nbc>0) { - TTriaList* triaListI = (*itPttI)->second; - for ( trI = triaListI->begin(); trI != triaListI->end(); ) - { - const SMDS_FaceOfNodes* FI = *trI; - - for ( itPttJ = aMergesJ.begin(); itPttJ != aMergesJ.end() && FI; ++itPttJ ) - { - TTriaList* triaListJ = (*itPttJ)->second; - for ( trJ = triaListJ->begin(); trJ != triaListJ->end(); ) - { - const SMDS_FaceOfNodes* FJ = *trJ; - - if( EqualTriangles(FI,FJ) ) - { - delete FI; - delete FJ; - FI = FJ = 0; - trI = triaListI->erase( trI ); - trJ = triaListJ->erase( trJ ); - break; // only one triangle of a pyramid can coincide with another pyramid - } - ++trJ; - } - } - if ( FI ) ++trI; // increament if triangle not deleted - } + // Merge the two pyramids and others already merged with them + MergePiramids( PrmI, PrmJ, meshDS, nodesToMove ); } + else { // nbc==0 - // set the common apex node to pyramids and triangles merged with J - for ( itPttJ = aMergesJ.begin(); itPttJ != aMergesJ.end(); ++itPttJ ) - { - const SMDS_MeshElement* Prm = (*itPttJ)->first; - TTriaList* triaList = (*itPttJ)->second; - - vector< const SMDS_MeshNode* > nodes( Prm->begin_nodes(), Prm->end_nodes() ); - nodes[4] = CommonNode; - meshDS->ChangeElementNodes( Prm, &nodes[0], nodes.size()); - - for ( TTriaList::iterator trIt = triaList->begin(); trIt != triaList->end(); ++trIt ) - { - SMDS_FaceOfNodes* Ftria = const_cast< SMDS_FaceOfNodes*>( *trIt ); - const SMDS_MeshNode* NF[3] = { CommonNode, Ftria->GetNode(1), Ftria->GetNode(2)}; - Ftria->ChangeNodes(NF, 3); + // decrease height of pyramids + gp_XYZ PCi(0,0,0), PCj(0,0,0); + for(k=0; k<4; k++) { + PCi += PsI[k].XYZ(); + PCj += PsJ[k].XYZ(); } + PCi /= 4; PCj /= 4; + gp_Vec VN1(PCi,PsI[4]); + gp_Vec VN2(PCj,PsJ[4]); + gp_Vec VI1(PCi,Pint); + gp_Vec VI2(PCj,Pint); + double ang1 = fabs(VN1.Angle(VI1)); + double ang2 = fabs(VN2.Angle(VI2)); + double coef1 = 0.5 - (( ang1(PrmI->GetNode(4)); + aNode1->setXYZ( PCi.X()+VN1.X(), PCi.Y()+VN1.Y(), PCi.Z()+VN1.Z() ); + SMDS_MeshNode* aNode2 = const_cast(PrmJ->GetNode(4)); + aNode2->setXYZ( PCj.X()+VN2.X(), PCj.Y()+VN2.Y(), PCj.Z()+VN2.Z() ); + nodesToMove.insert( aNode1 ); + nodesToMove.insert( aNode2 ); } + // fix intersections that could appear after apex movement + MergeAdjacent( PrmI, aMesh, nodesToMove ); + MergeAdjacent( PrmJ, aMesh, nodesToMove ); - // join MergesInfo of merged pyramids - for ( k = 0, itPttI = aMergesI.begin(); k < nbI; ++itPttI, ++k ) - { - const SMDS_MeshElement* PrmI = (*itPttI)->first; - list< TPyram2Trias::iterator >& merges = MergesInfo[ PrmI ]; - merges.insert( merges.end(), aMergesJ.begin(), aMergesJ.end() ); - } - for ( k = 0, itPttJ = aMergesJ.begin(); k < nbJ; ++itPttJ, ++k ) - { - const SMDS_MeshElement* PrmJ = (*itPttJ)->first; - list< TPyram2Trias::iterator >& merges = MergesInfo[ PrmJ ]; - merges.insert( merges.end(), aMergesI.begin(), aMergesI.end() ); - } + } // end if(hasInt) + } // loop on suspectPyrams + } // loop on 4 base nodes of PrmI - // removing node - meshDS->RemoveNode(Nrem); - } - else { // nbc==0 + } // loop on all pyramids - // decrease height of pyramids - gp_XYZ PC1(0,0,0), PC2(0,0,0); - for(k=0; k<4; k++) { - PC1 += PsI[k].XYZ(); - PC2 += PsJ[k].XYZ(); - } - PC1 /= 4; PC2 /= 4; - gp_Vec VN1(PC1,PsI[4]); - gp_Vec VI1(PC1,Pint); - gp_Vec VN2(PC2,PsJ[4]); - gp_Vec VI2(PC2,Pint); - double ang1 = fabs(VN1.Angle(VI1)); - double ang2 = fabs(VN2.Angle(VI2)); - double h1,h2; - if(ang1>PI/3.) - h1 = VI1.Magnitude()/2; - else - h1 = VI1.Magnitude()*cos(ang1); - if(ang2>PI/3.) - h2 = VI2.Magnitude()/2; - else - h2 = VI2.Magnitude()*cos(ang2); - double coef1 = 0.5; - if(ang1(PrmI->GetNode(4)); - aNode1->setXYZ( PC1.X()+VN1.X(), PC1.Y()+VN1.Y(), PC1.Z()+VN1.Z() ); - SMDS_MeshNode* aNode2 = const_cast(PrmJ->GetNode(4)); - aNode2->setXYZ( PC2.X()+VN2.X(), PC2.Y()+VN2.Y(), PC2.Z()+VN2.Z() ); - NeedMove = true; - } - } // end if(hasInt) - } - if( NeedMove && !meshDS->IsEmbeddedMode() ) - { - const SMDS_MeshNode* apex = PrmI->GetNode( 4 ); - meshDS->MoveNode( apex, apex->X(), apex->Y(), apex->Z() ); - } + if( !nodesToMove.empty() && !meshDS->IsEmbeddedMode() ) + { + set::iterator n = nodesToMove.begin(); + for ( ; n != nodesToMove.end(); ++n ) + meshDS->MoveNode( *n, (*n)->X(), (*n)->Y(), (*n)->Z() ); } // rebind triangles of pyramids sharing the same base quadrangle to the first @@ -931,10 +1173,23 @@ bool StdMeshers_QuadToTriaAdaptor::Compute2ndPart(SMESH_Mesh& aMesh) if ( q2t->first == q2tPrev->first ) q2tPrev->second.splice( q2tPrev->second.end(), q2t->second ); } + // delete removed triangles and count resulting nb of triangles + for ( q2t = myResMap.begin(); q2t != myResMap.end(); ++q2t ) + { + TTriaList & trias = q2t->second; + for ( TTriaList::iterator tri = trias.begin(); tri != trias.end(); ) + if ( ((const Q2TAdaptor_Triangle*) *tri)->IsRemoved() ) + delete *tri, trias.erase( tri++ ); + else + tri++, myNbTriangles++; + } - myPyram2Trias.clear(); // no more needed + myPyramids.clear(); // no more needed myDegNodes.clear(); + delete myElemSearcher; + myElemSearcher=0; + return true; } @@ -944,11 +1199,8 @@ bool StdMeshers_QuadToTriaAdaptor::Compute2ndPart(SMESH_Mesh& aMesh) */ //================================================================================ -const list* StdMeshers_QuadToTriaAdaptor::GetTriangles (const SMDS_MeshElement* aQuad) +const list* StdMeshers_QuadToTriaAdaptor::GetTriangles (const SMDS_MeshElement* aQuad) { TQuad2Trias::iterator it = myResMap.find(aQuad); - if( it != myResMap.end() ) { - return & it->second; - } - return 0; + return ( it != myResMap.end() ? & it->second : 0 ); } diff --git a/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.hxx b/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.hxx index 79017c20d..ceccb2542 100644 --- a/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.hxx +++ b/src/StdMeshers/StdMeshers_QuadToTriaAdaptor.hxx @@ -25,14 +25,14 @@ #define _SMESH_QuadToTriaAdaptor_HXX_ #include "SMESH_StdMeshers.hxx" -#include "SMDS_FaceOfNodes.hxx" class SMESH_Mesh; +class SMESH_ElementSearcher; class SMDS_MeshElement; class SMDS_MeshNode; -class Handle(TColgp_HArray1OfPnt); -class Handle(TColgp_HArray1OfVec); -class TopoDS_Shape; +class SMDS_MeshFace; +class Handle_TColgp_HArray1OfPnt; +class Handle_TColgp_HArray1OfVec; class gp_Pnt; class gp_Vec; @@ -41,9 +41,15 @@ class gp_Vec; #include #include +#include + +/*! + * \brief "Transforms" quadrilateral faces into triangular ones by creation of pyramids + */ class STDMESHERS_EXPORT StdMeshers_QuadToTriaAdaptor { public: + StdMeshers_QuadToTriaAdaptor(); ~StdMeshers_QuadToTriaAdaptor(); @@ -51,15 +57,22 @@ public: bool Compute(SMESH_Mesh& aMesh); - const std::list* GetTriangles(const SMDS_MeshElement* aFace); + const std::list* GetTriangles(const SMDS_MeshElement* aFace); + + /*! + * \brief Return sum of generated and already present triangles + */ + int TotalNbOfTriangles() const { return myNbTriangles; } + + TopoDS_Shape GetShape() const { return myShape; } protected: //bool CheckDegenerate(const SMDS_MeshElement* aFace); int Preparation(const SMDS_MeshElement* face, - Handle(TColgp_HArray1OfPnt)& PN, - Handle(TColgp_HArray1OfVec)& VN, + Handle_TColgp_HArray1OfPnt& PN, + Handle_TColgp_HArray1OfVec& VN, std::vector& FNodes, gp_Pnt& PC, gp_Vec& VNorm, const SMDS_MeshElement** volumes=0); @@ -67,19 +80,24 @@ protected: bool CheckIntersection(const gp_Pnt& P, const gp_Pnt& PC, gp_Pnt& Pint, SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, - const TopoDS_Shape& NotCheckedFace); + const SMDS_MeshElement* NotCheckedFace); bool Compute2ndPart(SMESH_Mesh& aMesh); - typedef std::list TTriaList; - typedef std::multimap TQuad2Trias; - typedef std::map TPyram2Trias; + + typedef std::list TTriaList; + typedef std::multimap TQuad2Trias; TQuad2Trias myResMap; - TPyram2Trias myPyram2Trias; + std::vector myPyramids; std::list< const SMDS_MeshNode* > myDegNodes; + const SMESH_ElementSearcher* myElemSearcher; + + int myNbTriangles; + + TopoDS_Shape myShape; }; #endif diff --git a/src/StdMeshers/StdMeshers_QuadrangleParams.cxx b/src/StdMeshers/StdMeshers_QuadrangleParams.cxx index 07cd7f649..c0e106364 100644 --- a/src/StdMeshers/StdMeshers_QuadrangleParams.cxx +++ b/src/StdMeshers/StdMeshers_QuadrangleParams.cxx @@ -16,12 +16,11 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // - // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_QuadrangleParams.cxx // Author : Sergey KUUL, OCC // Module : SMESH -// + #include "StdMeshers_QuadrangleParams.hxx" #include "SMESH_Algo.hxx" @@ -41,38 +40,36 @@ using namespace std; //============================================================================= /*! - * + * */ //============================================================================= - StdMeshers_QuadrangleParams::StdMeshers_QuadrangleParams(int hypId, int studyId, SMESH_Gen * gen) - :SMESH_Hypothesis(hypId, studyId, gen) + : SMESH_Hypothesis(hypId, studyId, gen) { _name = "QuadrangleParams"; _param_algo_dim = 2; _triaVertexID = -1; + _quadType = QUAD_STANDARD; } //============================================================================= /*! - * + * */ //============================================================================= - StdMeshers_QuadrangleParams::~StdMeshers_QuadrangleParams() { } //============================================================================= /*! - * + * */ //============================================================================= - -void StdMeshers_QuadrangleParams::SetTriaVertex(int id) +void StdMeshers_QuadrangleParams::SetTriaVertex (int id) { - if ( id != _triaVertexID ) { + if (id != _triaVertexID) { _triaVertexID = id; NotifySubMeshesHypothesisModification(); } @@ -80,22 +77,36 @@ void StdMeshers_QuadrangleParams::SetTriaVertex(int id) //============================================================================= /*! - * + * */ //============================================================================= +void StdMeshers_QuadrangleParams::SetQuadType (StdMeshers_QuadType type) +{ + if (type != _quadType) { + _quadType = type; + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +/*! + * + */ +//============================================================================= ostream & StdMeshers_QuadrangleParams::SaveTo(ostream & save) { - save << _triaVertexID << " " << _objEntry; + if (_objEntry.size() == 0) + save << _triaVertexID << " UNDEFINED " << int(_quadType); + else + save << _triaVertexID << " " << _objEntry << " " << int(_quadType); return save; } //============================================================================= /*! - * + * */ //============================================================================= - istream & StdMeshers_QuadrangleParams::LoadFrom(istream & load) { bool isOK = true; @@ -104,16 +115,22 @@ istream & StdMeshers_QuadrangleParams::LoadFrom(istream & load) load.clear(ios::badbit | load.rdstate()); isOK = (load >> _objEntry); + if (!isOK) + load.clear(ios::badbit | load.rdstate()); + + int type; + isOK = (load >> type); + if (isOK) + _quadType = StdMeshers_QuadType(type); return load; } //============================================================================= /*! - * + * */ //============================================================================= - ostream & operator <<(ostream & save, StdMeshers_QuadrangleParams & hyp) { return hyp.SaveTo( save ); @@ -121,10 +138,9 @@ ostream & operator <<(ostream & save, StdMeshers_QuadrangleParams & hyp) //============================================================================= /*! - * + * */ //============================================================================= - istream & operator >>(istream & load, StdMeshers_QuadrangleParams & hyp) { return hyp.LoadFrom( load ); @@ -138,7 +154,6 @@ istream & operator >>(istream & load, StdMeshers_QuadrangleParams & hyp) * \retval bool - true if parameter values have been successfully defined */ //================================================================================ - bool StdMeshers_QuadrangleParams::SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape) { @@ -154,10 +169,8 @@ bool StdMeshers_QuadrangleParams::SetParametersByMesh(const SMESH_Mesh* theMesh, * \retval bool - true if parameter values have been successfully defined */ //================================================================================ - bool StdMeshers_QuadrangleParams::SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* /*mesh*/) { return true; } - diff --git a/src/StdMeshers/StdMeshers_QuadrangleParams.hxx b/src/StdMeshers/StdMeshers_QuadrangleParams.hxx index da37f0755..d880c5008 100644 --- a/src/StdMeshers/StdMeshers_QuadrangleParams.hxx +++ b/src/StdMeshers/StdMeshers_QuadrangleParams.hxx @@ -16,22 +16,29 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // - // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_QuadrangleParams.hxx // Author : Sergey KUUL, OCC // Module : SMESH -// + #ifndef _SMESH_QUADRANGLEPARAMS_HXX_ #define _SMESH_QUADRANGLEPARAMS_HXX_ - - #include "SMESH_StdMeshers.hxx" #include "SMESH_Hypothesis.hxx" #include "Utils_SALOME_Exception.hxx" +enum StdMeshers_QuadType + { + QUAD_STANDARD, + QUAD_TRIANGLE_PREF, + QUAD_QUADRANGLE_PREF, + QUAD_QUADRANGLE_PREF_REVERSED, + QUAD_REDUCED, + QUAD_NB_TYPES + }; + class STDMESHERS_EXPORT StdMeshers_QuadrangleParams: public SMESH_Hypothesis { @@ -39,13 +46,14 @@ public: StdMeshers_QuadrangleParams(int hypId, int studyId, SMESH_Gen* gen); virtual ~StdMeshers_QuadrangleParams(); - void SetTriaVertex(int id); - - void SetObjectEntry( const char* entry ) { _objEntry = entry; } + void SetTriaVertex (int id); + int GetTriaVertex() const { return _triaVertexID; } + void SetObjectEntry (const char* entry) { _objEntry = entry; } const char* GetObjectEntry() { return _objEntry.c_str(); } - int GetTriaVertex() const { return _triaVertexID; } + void SetQuadType (StdMeshers_QuadType type); + StdMeshers_QuadType GetQuadType() const { return _quadType; } virtual std::ostream & SaveTo(std::ostream & save); virtual std::istream & LoadFrom(std::istream & load); @@ -71,8 +79,9 @@ public: const SMESH_Mesh* theMesh=0); protected: - int _triaVertexID; - std::string _objEntry; + int _triaVertexID; + std::string _objEntry; + StdMeshers_QuadType _quadType; }; #endif diff --git a/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx b/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx index 1c0cf5e5b..1075db412 100644 --- a/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx +++ b/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx @@ -18,14 +18,11 @@ // 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 : implementaion of SMESH idl descriptions // File : StdMeshers_Quadrangle_2D.cxx -// Moved here from SMESH_Quadrangle_2D.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// + #include "StdMeshers_Quadrangle_2D.hxx" #include "StdMeshers_FaceSide.hxx" @@ -49,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -116,69 +114,75 @@ bool StdMeshers_Quadrangle_2D::CheckHypothesis bool isOk = true; aStatus = SMESH_Hypothesis::HYP_OK; - const list &hyps = + const list & hyps = GetUsedHypothesis(aMesh, aShape, false); - const SMESHDS_Hypothesis *theHyp = 0; - - if( hyps.size() == 1 ) { - myTriaVertexID = -1; - theHyp = hyps.front(); - if(strcmp("QuadrangleParams", theHyp->GetName()) == 0) { - const StdMeshers_QuadrangleParams* theHyp1 = - (const StdMeshers_QuadrangleParams*)theHyp; - myTriaVertexID = theHyp1->GetTriaVertex(); - myQuadranglePreference= false; - myTrianglePreference= false; - } - if(strcmp("QuadranglePreference", theHyp->GetName()) == 0) { - myQuadranglePreference= true; - myTrianglePreference= false; - myTriaVertexID = -1; - } - else if(strcmp("TrianglePreference", theHyp->GetName()) == 0){ - myQuadranglePreference= false; - myTrianglePreference= true; - myTriaVertexID = -1; + const SMESHDS_Hypothesis * aHyp = 0; + + myTriaVertexID = -1; + myQuadType = QUAD_STANDARD; + myQuadranglePreference = false; + myTrianglePreference = false; + + bool isFirstParams = true; + + // First assigned hypothesis (if any) is processed now + if (hyps.size() > 0) { + aHyp = hyps.front(); + if (strcmp("QuadrangleParams", aHyp->GetName()) == 0) { + const StdMeshers_QuadrangleParams* aHyp1 = + (const StdMeshers_QuadrangleParams*)aHyp; + myTriaVertexID = aHyp1->GetTriaVertex(); + myQuadType = aHyp1->GetQuadType(); + if (myQuadType == QUAD_QUADRANGLE_PREF || + myQuadType == QUAD_QUADRANGLE_PREF_REVERSED) + myQuadranglePreference = true; + else if (myQuadType == QUAD_TRIANGLE_PREF) + myTrianglePreference = true; + } + else if (strcmp("QuadranglePreference", aHyp->GetName()) == 0) { + isFirstParams = false; + myQuadranglePreference = true; + } + else if (strcmp("TrianglePreference", aHyp->GetName()) == 0){ + isFirstParams = false; + myTrianglePreference = true; + } + else { + isFirstParams = false; } } - else if( hyps.size() > 1 ) { - theHyp = hyps.front(); - if(strcmp("QuadrangleParams", theHyp->GetName()) == 0) { - const StdMeshers_QuadrangleParams* theHyp1 = - (const StdMeshers_QuadrangleParams*)theHyp; - myTriaVertexID = theHyp1->GetTriaVertex(); - theHyp = hyps.back(); - if(strcmp("QuadranglePreference", theHyp->GetName()) == 0) { - myQuadranglePreference= true; - myTrianglePreference= false; + // Second(last) assigned hypothesis (if any) is processed now + if (hyps.size() > 1) { + aHyp = hyps.back(); + if (isFirstParams) { + if (strcmp("QuadranglePreference", aHyp->GetName()) == 0) { + myQuadranglePreference = true; + myTrianglePreference = false; + myQuadType = QUAD_STANDARD; } - else if(strcmp("TrianglePreference", theHyp->GetName()) == 0){ - myQuadranglePreference= false; - myTrianglePreference= true; + else if (strcmp("TrianglePreference", aHyp->GetName()) == 0){ + myQuadranglePreference = false; + myTrianglePreference = true; + myQuadType = QUAD_STANDARD; } } else { - if(strcmp("QuadranglePreference", theHyp->GetName()) == 0) { - myQuadranglePreference= true; - myTrianglePreference= false; + const StdMeshers_QuadrangleParams* aHyp2 = + (const StdMeshers_QuadrangleParams*)aHyp; + myTriaVertexID = aHyp2->GetTriaVertex(); + + if (!myQuadranglePreference && !myTrianglePreference) { // priority of hypos + myQuadType = aHyp2->GetQuadType(); + if (myQuadType == QUAD_QUADRANGLE_PREF || + myQuadType == QUAD_QUADRANGLE_PREF_REVERSED) + myQuadranglePreference = true; + else if (myQuadType == QUAD_TRIANGLE_PREF) + myTrianglePreference = true; } - else if(strcmp("TrianglePreference", theHyp->GetName()) == 0){ - myQuadranglePreference= false; - myTrianglePreference= true; - } - const StdMeshers_QuadrangleParams* theHyp2 = - (const StdMeshers_QuadrangleParams*)hyps.back(); - myTriaVertexID = theHyp2->GetTriaVertex(); } } - else { - myQuadranglePreference = false; - myTrianglePreference = false; - myTriaVertexID = -1; - } - return isOk; } @@ -197,17 +201,17 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); aMesh.GetSubMesh(aShape); - SMESH_MesherHelper helper(aMesh); + SMESH_MesherHelper helper (aMesh); myTool = &helper; _quadraticMesh = myTool->IsQuadraticSubMesh(aShape); - FaceQuadStruct *quad = CheckNbEdges( aMesh, aShape ); - std::auto_ptr quadDeleter( quad ); // to delete quad at exit from Compute() + FaceQuadStruct *quad = CheckNbEdges(aMesh, aShape); + std::auto_ptr quadDeleter (quad); // to delete quad at exit from Compute() if (!quad) return false; - if(myQuadranglePreference) { + if (myQuadranglePreference) { int n1 = quad->side[0]->NbPoints(); int n2 = quad->side[1]->NbPoints(); int n3 = quad->side[2]->NbPoints(); @@ -215,12 +219,27 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, int nfull = n1+n2+n3+n4; int ntmp = nfull/2; ntmp = ntmp*2; - if( nfull==ntmp && ( (n1!=n3) || (n2!=n4) ) ) { + if (nfull == ntmp && ((n1 != n3) || (n2 != n4))) { // special path for using only quandrangle faces bool ok = ComputeQuadPref(aMesh, aShape, quad); return ok; } } + else if (myQuadType == QUAD_REDUCED) { + int n1 = quad->side[0]->NbPoints(); + int n2 = quad->side[1]->NbPoints(); + int n3 = quad->side[2]->NbPoints(); + int n4 = quad->side[3]->NbPoints(); + int n13 = n1 - n3; + int n24 = n2 - n4; + int n13tmp = n13/2; n13tmp = n13tmp*2; + int n24tmp = n24/2; n24tmp = n24tmp*2; + if ((n1 == n3 && n2 != n4 && n24tmp == n24) || + (n2 == n4 && n1 != n3 && n13tmp == n13)) { + bool ok = ComputeReduced(aMesh, aShape, quad); + return ok; + } + } // set normalized grid on unit square in parametric domain @@ -242,7 +261,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, Handle(Geom_Surface) S = BRep_Tool::Surface(F); // internal mesh nodes - int i, j, geomFaceID = meshDS->ShapeToIndex( F ); + int i, j, geomFaceID = meshDS->ShapeToIndex(F); for (i = 1; i < nbhoriz - 1; i++) { for (j = 1; j < nbvertic - 1; j++) { int ij = j * nbhoriz + i; @@ -287,19 +306,19 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, c = quad->uv_grid[(j + 1) * nbhoriz + i + 1].node; d = quad->uv_grid[(j + 1) * nbhoriz + i].node; SMDS_MeshFace* face = myTool->AddFace(a, b, c, d); - if(face) { + if (face) { meshDS->SetMeshElementOnShape(face, geomFaceID); } } } - const vector& uv_e0 = quad->side[0]->GetUVPtStruct(true,0 ); + const vector& uv_e0 = quad->side[0]->GetUVPtStruct(true,0); const vector& uv_e1 = quad->side[1]->GetUVPtStruct(false,1); - const vector& uv_e2 = quad->side[2]->GetUVPtStruct(true,1 ); + const vector& uv_e2 = quad->side[2]->GetUVPtStruct(true,1); const vector& uv_e3 = quad->side[3]->GetUVPtStruct(false,0); - if ( uv_e0.empty() || uv_e1.empty() || uv_e2.empty() || uv_e3.empty() ) - return error( COMPERR_BAD_INPUT_MESH ); + if (uv_e0.empty() || uv_e1.empty() || uv_e2.empty() || uv_e3.empty()) + return error(COMPERR_BAD_INPUT_MESH); double eps = Precision::Confusion(); @@ -364,7 +383,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, if (near == g) { // make triangle SMDS_MeshFace* face = myTool->AddFace(a, b, c); - if(face) meshDS->SetMeshElementOnShape(face, geomFaceID); + if (face) meshDS->SetMeshElementOnShape(face, geomFaceID); } else { // make quadrangle if (near - 1 < ilow) @@ -373,9 +392,9 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, d = quad->uv_grid[nbhoriz + near - 1].node; //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d); - if(!myTrianglePreference){ + if (!myTrianglePreference){ SMDS_MeshFace* face = myTool->AddFace(a, b, c, d); - if(face) meshDS->SetMeshElementOnShape(face, geomFaceID); + if (face) meshDS->SetMeshElementOnShape(face, geomFaceID); } else { SplitQuad(meshDS, geomFaceID, a, b, c, d); @@ -390,7 +409,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, else d = quad->uv_grid[nbhoriz + k - 1].node; SMDS_MeshFace* face = myTool->AddFace(a, c, d); - if(face) meshDS->SetMeshElementOnShape(face, geomFaceID); + if (face) meshDS->SetMeshElementOnShape(face, geomFaceID); } } g = near; @@ -452,7 +471,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, if (near == g) { // make triangle SMDS_MeshFace* face = myTool->AddFace(a, b, c); - if(face) meshDS->SetMeshElementOnShape(face, geomFaceID); + if (face) meshDS->SetMeshElementOnShape(face, geomFaceID); } else { // make quadrangle if (near + 1 > iup) @@ -460,9 +479,9 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, else d = quad->uv_grid[nbhoriz*(nbvertic - 2) + near + 1].node; //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d); - if(!myTrianglePreference){ + if (!myTrianglePreference){ SMDS_MeshFace* face = myTool->AddFace(a, b, c, d); - if(face) meshDS->SetMeshElementOnShape(face, geomFaceID); + if (face) meshDS->SetMeshElementOnShape(face, geomFaceID); } else { SplitQuad(meshDS, geomFaceID, a, b, c, d); @@ -476,7 +495,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, else d = quad->uv_grid[nbhoriz*(nbvertic - 2) + k + 1].node; SMDS_MeshFace* face = myTool->AddFace(a, c, d); - if(face) meshDS->SetMeshElementOnShape(face, geomFaceID); + if (face) meshDS->SetMeshElementOnShape(face, geomFaceID); } } g = near; @@ -524,7 +543,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, if (near == g) { // make triangle SMDS_MeshFace* face = myTool->AddFace(a, b, c); - if(face) meshDS->SetMeshElementOnShape(face, geomFaceID); + if (face) meshDS->SetMeshElementOnShape(face, geomFaceID); } else { // make quadrangle if (near - 1 < jlow) @@ -533,9 +552,9 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, d = quad->uv_grid[nbhoriz*near - 2].node; //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d); - if(!myTrianglePreference){ + if (!myTrianglePreference){ SMDS_MeshFace* face = myTool->AddFace(a, b, c, d); - if(face) meshDS->SetMeshElementOnShape(face, geomFaceID); + if (face) meshDS->SetMeshElementOnShape(face, geomFaceID); } else { SplitQuad(meshDS, geomFaceID, a, b, c, d); @@ -549,7 +568,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, else d = quad->uv_grid[nbhoriz*k - 2].node; SMDS_MeshFace* face = myTool->AddFace(a, c, d); - if(face) meshDS->SetMeshElementOnShape(face, geomFaceID); + if (face) meshDS->SetMeshElementOnShape(face, geomFaceID); } } g = near; @@ -594,7 +613,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, if (near == g) { // make triangle SMDS_MeshFace* face = myTool->AddFace(a, b, c); - if(face) meshDS->SetMeshElementOnShape(face, geomFaceID); + if (face) meshDS->SetMeshElementOnShape(face, geomFaceID); } else { // make quadrangle if (near + 1 > jup) @@ -602,9 +621,9 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, else d = quad->uv_grid[nbhoriz*(near + 1) + 1].node; //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d); - if(!myTrianglePreference){ + if (!myTrianglePreference){ SMDS_MeshFace* face = myTool->AddFace(a, b, c, d); - if(face) meshDS->SetMeshElementOnShape(face, geomFaceID); + if (face) meshDS->SetMeshElementOnShape(face, geomFaceID); } else { SplitQuad(meshDS, geomFaceID, a, b, c, d); @@ -618,7 +637,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, else d = quad->uv_grid[nbhoriz*(k + 1) + 1].node; SMDS_MeshFace* face = myTool->AddFace(a, c, d); - if(face) meshDS->SetMeshElementOnShape(face, geomFaceID); + if (face) meshDS->SetMeshElementOnShape(face, geomFaceID); } } g = near; @@ -647,17 +666,17 @@ bool StdMeshers_Quadrangle_2D::Evaluate(SMESH_Mesh& aMesh, std::vector aNbNodes(4); bool IsQuadratic = false; - if( !CheckNbEdgesForEvaluate( aMesh, aShape, aResMap, aNbNodes, IsQuadratic ) ) { + if (!CheckNbEdgesForEvaluate(aMesh, aShape, aResMap, aNbNodes, IsQuadratic)) { std::vector aResVec(SMDSEntity_Last); - for(int i=SMDSEntity_Node; iGetComputeError(); - smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); + smError.reset(new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); return false; } - if(myQuadranglePreference) { + if (myQuadranglePreference) { int n1 = aNbNodes[0]; int n2 = aNbNodes[1]; int n3 = aNbNodes[2]; @@ -665,7 +684,7 @@ bool StdMeshers_Quadrangle_2D::Evaluate(SMESH_Mesh& aMesh, int nfull = n1+n2+n3+n4; int ntmp = nfull/2; ntmp = ntmp*2; - if( nfull==ntmp && ( (n1!=n3) || (n2!=n4) ) ) { + if (nfull==ntmp && ((n1!=n3) || (n2!=n4))) { // special path for using only quandrangle faces return EvaluateQuadPref(aMesh, aShape, aNbNodes, aResMap, IsQuadratic); //return true; @@ -685,27 +704,27 @@ bool StdMeshers_Quadrangle_2D::Evaluate(SMESH_Mesh& aMesh, int dv = Max(nbright, nbleft) - nbvertic; //int kdh = 0; - //if(dh>0) kdh = 1; + //if (dh>0) kdh = 1; //int kdv = 0; - //if(dv>0) kdv = 1; + //if (dv>0) kdv = 1; int nbNodes = (nbhoriz-2)*(nbvertic-2); //int nbFaces3 = dh + dv + kdh*(nbvertic-1)*2 + kdv*(nbhoriz-1)*2; int nbFaces3 = dh + dv; - //if( kdh==1 && kdv==1 ) nbFaces3 -= 2; - //if( dh>0 && dv>0 ) nbFaces3 -= 2; + //if (kdh==1 && kdv==1) nbFaces3 -= 2; + //if (dh>0 && dv>0) nbFaces3 -= 2; //int nbFaces4 = (nbhoriz-1-kdh)*(nbvertic-1-kdv); int nbFaces4 = (nbhoriz-1)*(nbvertic-1); std::vector aVec(SMDSEntity_Last); - for(int i=SMDSEntity_Node; i= TopAbs_INTERNAL ) F.Orientation( TopAbs_FORWARD ); const bool ignoreMediumNodes = _quadraticMesh; // verify 1 wire only, with 4 edges @@ -775,113 +795,113 @@ FaceQuadStruct* StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh & aMes int nbSides = 0; list< TopoDS_Edge >::iterator edgeIt = edges.begin(); - if ( nbEdgesInWire.front() == 3 ) // exactly 3 edges + if (nbEdgesInWire.front() == 3) // exactly 3 edges { 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"; } else { TopoDS_Vertex V = TopoDS::Vertex(meshDS->IndexToShape(myTriaVertexID)); - if ( !V.IsNull() ) { + if (!V.IsNull()) { TopoDS_Edge E1,E2,E3; - for(; edgeIt != edges.end(); ++edgeIt) { + for (; edgeIt != edges.end(); ++edgeIt) { TopoDS_Edge E = *edgeIt; TopoDS_Vertex VF, VL; TopExp::Vertices(E, VF, VL, true); - if( VF.IsSame(V) ) + if (VF.IsSame(V)) E1 = E; - else if( VL.IsSame(V) ) + else if (VL.IsSame(V)) E3 = E; else E2 = E; } - if ( !E1.IsNull() && !E2.IsNull() && !E3.IsNull() ) + if (!E1.IsNull() && !E2.IsNull() && !E3.IsNull()) { - quad->side.push_back( new StdMeshers_FaceSide(F, E1, &aMesh, true, ignoreMediumNodes)); - quad->side.push_back( new StdMeshers_FaceSide(F, E2, &aMesh, true, ignoreMediumNodes)); - quad->side.push_back( new StdMeshers_FaceSide(F, E3, &aMesh, false,ignoreMediumNodes)); + quad->side.push_back(new StdMeshers_FaceSide(F, E1, &aMesh, true, ignoreMediumNodes)); + quad->side.push_back(new StdMeshers_FaceSide(F, E2, &aMesh, true, ignoreMediumNodes)); + quad->side.push_back(new StdMeshers_FaceSide(F, E3, &aMesh, false,ignoreMediumNodes)); const vector& UVPSleft = quad->side[0]->GetUVPtStruct(true,0); /* vector& UVPStop = */quad->side[1]->GetUVPtStruct(false,1); /* vector& UVPSright = */quad->side[2]->GetUVPtStruct(true,1); const SMDS_MeshNode* aNode = UVPSleft[0].node; - gp_Pnt2d aPnt2d( UVPSleft[0].u, UVPSleft[0].v ); - quad->side.push_back( new StdMeshers_FaceSide(aNode, aPnt2d, quad->side[1])); + gp_Pnt2d aPnt2d(UVPSleft[0].u, UVPSleft[0].v); + quad->side.push_back(new StdMeshers_FaceSide(aNode, aPnt2d, quad->side[1])); return quad; } } comment << "Invalid Base vertex parameter: " << myTriaVertexID << " is not among ["; TopTools_MapOfShape vMap; - for ( TopExp_Explorer v( aShape, TopAbs_VERTEX ); v.More(); v.Next()) - if ( vMap.Add( v.Current() )) - comment << meshDS->ShapeToIndex( v.Current() ) << ( vMap.Extent()==3 ? "]" : ", "); + for (TopExp_Explorer v(aShape, TopAbs_VERTEX); v.More(); v.Next()) + if (vMap.Add(v.Current())) + comment << meshDS->ShapeToIndex(v.Current()) << (vMap.Extent()==3 ? "]" : ", "); } - error( comment ); + error(comment); delete quad; return quad = 0; } - else if ( nbEdgesInWire.front() == 4 ) { // exactly 4 edges - for ( ; edgeIt != edges.end(); ++edgeIt, nbSides++ ) - quad->side.push_back( new StdMeshers_FaceSide(F, *edgeIt, &aMesh, + 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 4 ) { // more than 4 edges - try to unite some + else if (nbEdgesInWire.front() > 4) { // more than 4 edges - try to unite some list< TopoDS_Edge > sideEdges; - while ( !edges.empty()) { + while (!edges.empty()) { sideEdges.clear(); - sideEdges.splice( sideEdges.end(), edges, edges.begin()); // edges.front() -> sideEdges.end() + sideEdges.splice(sideEdges.end(), edges, edges.begin()); // edges.front() -> sideEdges.end() bool sameSide = true; - while ( !edges.empty() && sameSide ) { - sameSide = SMESH_Algo::IsContinuous( sideEdges.back(), edges.front() ); - if ( sameSide ) - sideEdges.splice( sideEdges.end(), edges, edges.begin()); + while (!edges.empty() && sameSide) { + sameSide = SMESH_Algo::IsContinuous(sideEdges.back(), edges.front()); + if (sameSide) + sideEdges.splice(sideEdges.end(), edges, edges.begin()); } - if ( nbSides == 0 ) { // go backward from the first edge + if (nbSides == 0) { // go backward from the first edge sameSide = true; - while ( !edges.empty() && sameSide ) { - sameSide = SMESH_Algo::IsContinuous( sideEdges.front(), edges.back() ); - if ( sameSide ) - sideEdges.splice( sideEdges.begin(), edges, --edges.end()); + while (!edges.empty() && sameSide) { + sameSide = SMESH_Algo::IsContinuous(sideEdges.front(), edges.back()); + if (sameSide) + sideEdges.splice(sideEdges.begin(), edges, --edges.end()); } } - quad->side.push_back( new StdMeshers_FaceSide(F, sideEdges, &aMesh, + quad->side.push_back(new StdMeshers_FaceSide(F, sideEdges, &aMesh, nbSidesside.clear(); quad->side.reserve(nbEdgesInWire.front()); nbSides = 0; SMESH_Block::GetOrderedEdges (F, V, edges, nbEdgesInWire); - while ( !edges.empty()) { + while (!edges.empty()) { sideEdges.clear(); - sideEdges.splice( sideEdges.end(), edges, edges.begin()); + sideEdges.splice(sideEdges.end(), edges, edges.begin()); bool sameSide = true; - while ( !edges.empty() && sameSide ) { + while (!edges.empty() && sameSide) { sameSide = - SMESH_Algo::IsContinuous( sideEdges.back(), edges.front() ) && - twoEdgesMeatAtVertex( sideEdges.back(), edges.front(), aMesh ); - if ( sameSide ) - sideEdges.splice( sideEdges.end(), edges, edges.begin()); + SMESH_Algo::IsContinuous(sideEdges.back(), edges.front()) && + twoEdgesMeatAtVertex(sideEdges.back(), edges.front(), aMesh); + if (sameSide) + sideEdges.splice(sideEdges.end(), edges, edges.begin()); } - if ( nbSides == 0 ) { // go backward from the first edge + if (nbSides == 0) { // go backward from the first edge sameSide = true; - while ( !edges.empty() && sameSide ) { + while (!edges.empty() && sameSide) { sameSide = - SMESH_Algo::IsContinuous( sideEdges.front(), edges.back() ) && - twoEdgesMeatAtVertex( sideEdges.front(), edges.back(), aMesh ); - if ( sameSide ) - sideEdges.splice( sideEdges.begin(), edges, --edges.end()); + SMESH_Algo::IsContinuous(sideEdges.front(), edges.back()) && + twoEdgesMeatAtVertex(sideEdges.front(), edges.back(), aMesh); + if (sameSide) + sideEdges.splice(sideEdges.begin(), edges, --edges.end()); } } - quad->side.push_back( new StdMeshers_FaceSide(F, sideEdges, &aMesh, + quad->side.push_back(new StdMeshers_FaceSide(F, sideEdges, &aMesh, nbSidesside[i]->NbEdges(); ++e ) - MESSAGE ( myTool->GetMeshDS()->ShapeToIndex( quad->side[i]->Edge( e )) << " " ); - MESSAGE ( ")\n" ); + MESSAGE ("StdMeshers_Quadrangle_2D. Edge IDs of " << nbSides << " sides:\n"); + for (int i = 0; i < nbSides; ++i) { + MESSAGE (" ("); + for (int e = 0; e < quad->side[i]->NbEdges(); ++e) + MESSAGE (myTool->GetMeshDS()->ShapeToIndex(quad->side[i]->Edge(e)) << " "); + MESSAGE (")\n"); } //cout << endl; #endif - if ( !nbSides ) + if (!nbSides) nbSides = nbEdgesInWire.front(); error(COMPERR_BAD_SHAPE, TComm("Face must have 4 sides but not ") << nbSides); delete quad; @@ -937,51 +957,51 @@ bool StdMeshers_Quadrangle_2D::CheckNbEdgesForEvaluate(SMESH_Mesh& aMesh, int nbSides = 0; list< TopoDS_Edge >::iterator edgeIt = edges.begin(); - SMESH_subMesh * sm = aMesh.GetSubMesh( *edgeIt ); + SMESH_subMesh * sm = aMesh.GetSubMesh(*edgeIt); MapShapeNbElemsItr anIt = aResMap.find(sm); - if(anIt==aResMap.end()) { + if (anIt==aResMap.end()) { return false; } std::vector aVec = (*anIt).second; IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]); - if ( nbEdgesInWire.front() == 3 ) { // exactly 3 edges - if(myTriaVertexID>0) { + if (nbEdgesInWire.front() == 3) { // exactly 3 edges + if (myTriaVertexID>0) { SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); TopoDS_Vertex V = TopoDS::Vertex(meshDS->IndexToShape(myTriaVertexID)); - if(!V.IsNull()) { + if (!V.IsNull()) { TopoDS_Edge E1,E2,E3; - for(; edgeIt != edges.end(); ++edgeIt) { + for (; edgeIt != edges.end(); ++edgeIt) { TopoDS_Edge E = TopoDS::Edge(*edgeIt); TopoDS_Vertex VF, VL; TopExp::Vertices(E, VF, VL, true); - if( VF.IsSame(V) ) + if (VF.IsSame(V)) E1 = E; - else if( VL.IsSame(V) ) + else if (VL.IsSame(V)) E3 = E; else E2 = E; } SMESH_subMesh * sm = aMesh.GetSubMesh(E1); MapShapeNbElemsItr anIt = aResMap.find(sm); - if(anIt==aResMap.end()) return false; + if (anIt==aResMap.end()) return false; std::vector aVec = (*anIt).second; - if(IsQuadratic) + if (IsQuadratic) aNbNodes[0] = (aVec[SMDSEntity_Node]-1)/2 + 2; else aNbNodes[0] = aVec[SMDSEntity_Node] + 2; sm = aMesh.GetSubMesh(E2); anIt = aResMap.find(sm); - if(anIt==aResMap.end()) return false; + if (anIt==aResMap.end()) return false; aVec = (*anIt).second; - if(IsQuadratic) + if (IsQuadratic) aNbNodes[1] = (aVec[SMDSEntity_Node]-1)/2 + 2; else aNbNodes[1] = aVec[SMDSEntity_Node] + 2; sm = aMesh.GetSubMesh(E3); anIt = aResMap.find(sm); - if(anIt==aResMap.end()) return false; + if (anIt==aResMap.end()) return false; aVec = (*anIt).second; - if(IsQuadratic) + if (IsQuadratic) aNbNodes[2] = (aVec[SMDSEntity_Node]-1)/2 + 2; else aNbNodes[2] = aVec[SMDSEntity_Node] + 2; @@ -991,50 +1011,50 @@ bool StdMeshers_Quadrangle_2D::CheckNbEdgesForEvaluate(SMESH_Mesh& aMesh, } } } - if ( nbEdgesInWire.front() == 4 ) { // exactly 4 edges - for(; edgeIt != edges.end(); edgeIt++) { - SMESH_subMesh * sm = aMesh.GetSubMesh( *edgeIt ); + if (nbEdgesInWire.front() == 4) { // exactly 4 edges + for (; edgeIt != edges.end(); edgeIt++) { + SMESH_subMesh * sm = aMesh.GetSubMesh(*edgeIt); MapShapeNbElemsItr anIt = aResMap.find(sm); - if(anIt==aResMap.end()) { + if (anIt==aResMap.end()) { return false; } std::vector aVec = (*anIt).second; - if(IsQuadratic) + if (IsQuadratic) aNbNodes[nbSides] = (aVec[SMDSEntity_Node]-1)/2 + 2; else aNbNodes[nbSides] = aVec[SMDSEntity_Node] + 2; nbSides++; } } - else if ( nbEdgesInWire.front() > 4 ) { // more than 4 edges - try to unite some + else if (nbEdgesInWire.front() > 4) { // more than 4 edges - try to unite some list< TopoDS_Edge > sideEdges; - while ( !edges.empty()) { + while (!edges.empty()) { sideEdges.clear(); - sideEdges.splice( sideEdges.end(), edges, edges.begin()); // edges.front() -> sideEdges.end() + sideEdges.splice(sideEdges.end(), edges, edges.begin()); // edges.front() -> sideEdges.end() bool sameSide = true; - while ( !edges.empty() && sameSide ) { - sameSide = SMESH_Algo::IsContinuous( sideEdges.back(), edges.front() ); - if ( sameSide ) - sideEdges.splice( sideEdges.end(), edges, edges.begin()); + while (!edges.empty() && sameSide) { + sameSide = SMESH_Algo::IsContinuous(sideEdges.back(), edges.front()); + if (sameSide) + sideEdges.splice(sideEdges.end(), edges, edges.begin()); } - if ( nbSides == 0 ) { // go backward from the first edge + if (nbSides == 0) { // go backward from the first edge sameSide = true; - while ( !edges.empty() && sameSide ) { - sameSide = SMESH_Algo::IsContinuous( sideEdges.front(), edges.back() ); - if ( sameSide ) - sideEdges.splice( sideEdges.begin(), edges, --edges.end()); + while (!edges.empty() && sameSide) { + sameSide = SMESH_Algo::IsContinuous(sideEdges.front(), edges.back()); + if (sameSide) + sideEdges.splice(sideEdges.begin(), edges, --edges.end()); } } list::iterator ite = sideEdges.begin(); aNbNodes[nbSides] = 1; - for(; ite!=sideEdges.end(); ite++) { - SMESH_subMesh * sm = aMesh.GetSubMesh( *ite ); + for (; ite!=sideEdges.end(); ite++) { + SMESH_subMesh * sm = aMesh.GetSubMesh(*ite); MapShapeNbElemsItr anIt = aResMap.find(sm); - if(anIt==aResMap.end()) { + if (anIt==aResMap.end()) { return false; } std::vector aVec = (*anIt).second; - if(IsQuadratic) + if (IsQuadratic) aNbNodes[nbSides] += (aVec[SMDSEntity_Node]-1)/2 + 1; else aNbNodes[nbSides] += aVec[SMDSEntity_Node] + 1; @@ -1045,37 +1065,37 @@ bool StdMeshers_Quadrangle_2D::CheckNbEdgesForEvaluate(SMESH_Mesh& aMesh, if (nbSides < 4) { nbSides = 0; SMESH_Block::GetOrderedEdges (F, V, edges, nbEdgesInWire); - while ( !edges.empty()) { + while (!edges.empty()) { sideEdges.clear(); - sideEdges.splice( sideEdges.end(), edges, edges.begin()); + sideEdges.splice(sideEdges.end(), edges, edges.begin()); bool sameSide = true; - while ( !edges.empty() && sameSide ) { + while (!edges.empty() && sameSide) { sameSide = - SMESH_Algo::IsContinuous( sideEdges.back(), edges.front() ) && - twoEdgesMeatAtVertex( sideEdges.back(), edges.front(), aMesh ); - if ( sameSide ) - sideEdges.splice( sideEdges.end(), edges, edges.begin()); + SMESH_Algo::IsContinuous(sideEdges.back(), edges.front()) && + twoEdgesMeatAtVertex(sideEdges.back(), edges.front(), aMesh); + if (sameSide) + sideEdges.splice(sideEdges.end(), edges, edges.begin()); } - if ( nbSides == 0 ) { // go backward from the first edge + if (nbSides == 0) { // go backward from the first edge sameSide = true; - while ( !edges.empty() && sameSide ) { + while (!edges.empty() && sameSide) { sameSide = - SMESH_Algo::IsContinuous( sideEdges.front(), edges.back() ) && - twoEdgesMeatAtVertex( sideEdges.front(), edges.back(), aMesh ); - if ( sameSide ) - sideEdges.splice( sideEdges.begin(), edges, --edges.end()); + SMESH_Algo::IsContinuous(sideEdges.front(), edges.back()) && + twoEdgesMeatAtVertex(sideEdges.front(), edges.back(), aMesh); + if (sameSide) + sideEdges.splice(sideEdges.begin(), edges, --edges.end()); } } list::iterator ite = sideEdges.begin(); aNbNodes[nbSides] = 1; - for(; ite!=sideEdges.end(); ite++) { - SMESH_subMesh * sm = aMesh.GetSubMesh( *ite ); + for (; ite!=sideEdges.end(); ite++) { + SMESH_subMesh * sm = aMesh.GetSubMesh(*ite); MapShapeNbElemsItr anIt = aResMap.find(sm); - if(anIt==aResMap.end()) { + if (anIt==aResMap.end()) { return false; } std::vector aVec = (*anIt).second; - if(IsQuadratic) + if (IsQuadratic) aNbNodes[nbSides] += (aVec[SMDSEntity_Node]-1)/2 + 1; else aNbNodes[nbSides] += aVec[SMDSEntity_Node] + 1; @@ -1085,7 +1105,7 @@ bool StdMeshers_Quadrangle_2D::CheckNbEdgesForEvaluate(SMESH_Mesh& aMesh, } } if (nbSides != 4) { - if ( !nbSides ) + if (!nbSides) nbSides = nbEdgesInWire.front(); error(COMPERR_BAD_SHAPE, TComm("Face must have 4 sides but not ") << nbSides); return false; @@ -1110,13 +1130,12 @@ FaceQuadStruct *StdMeshers_Quadrangle_2D::CheckAnd2Dcompute FaceQuadStruct *quad = CheckNbEdges(aMesh, aShape); - if(!quad) return 0; + 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; + if (!stat) { + if (quad) delete quad; quad = 0; } @@ -1140,13 +1159,21 @@ faceQuadStruct::~faceQuadStruct() namespace { inline const vector& GetUVPtStructIn(FaceQuadStruct* 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 == BOTTOM_SIDE || i == TOP_SIDE); + double constValue = (i == BOTTOM_SIDE || i == 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, + 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) + { + return + ((1 - y) * p0 + x * p1 + y * p2 + (1 - x) * p3 ) - + ((1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3); + } } //============================================================================= @@ -1193,14 +1220,14 @@ 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"); - return error( COMPERR_BAD_INPUT_MESH ); + if (uv_e0.empty() || uv_e1.empty() || uv_e2.empty() || uv_e3.empty()) + //return error("Can't find nodes on sides"); + return error(COMPERR_BAD_INPUT_MESH); // nodes Id on "in" edges if (! quad->isEdgeOut[0]) { @@ -1253,10 +1280,10 @@ bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh, } // 4 --- projection on 2d domain (u,v) - gp_UV a0( uv_e0.front().u, uv_e0.front().v ); - gp_UV a1( uv_e0.back().u, uv_e0.back().v ); - gp_UV a2( uv_e2.back().u, uv_e2.back().v ); - gp_UV a3( uv_e2.front().u, uv_e2.front().v ); + gp_UV a0(uv_e0.front().u, uv_e0.front().v); + gp_UV a1(uv_e0.back().u, uv_e0.back().v); + gp_UV a2(uv_e2.back().u, uv_e2.back().v); + gp_UV a3(uv_e2.front().u, uv_e2.front().v); for (int i = 0; i < nbhoriz; i++) { for (int j = 0; j < nbvertic; j++) { @@ -1274,8 +1301,7 @@ bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh, gp_UV p2 = quad->side[2]->Value2d(param_2).XY(); gp_UV p3 = quad->side[3]->Value2d(param_3).XY(); - gp_UV uv = (1 - y) * p0 + x * p1 + y * p2 + (1 - x) * p3; - uv -= (1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3; + 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(); @@ -1292,11 +1318,11 @@ bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh, static void ShiftQuad(FaceQuadStruct* quad, const int num, bool) { 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 ) + 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 ]; } @@ -1312,9 +1338,9 @@ static gp_UV CalcUV(double x0, double x1, double y0, double y1, 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_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_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)); @@ -1330,9 +1356,7 @@ static gp_UV CalcUV(double x0, double x1, double y0, double y1, gp_UV p2 = quad->side[TOP_SIDE ]->Value2d(param_t).XY(); gp_UV p3 = quad->side[LEFT_SIDE ]->Value2d(param_l).XY(); - gp_UV uv = p0 * (1 - y) + p1 * x + p2 * y + p3 * (1 - x); - - uv -= (1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3; + gp_UV uv = CalcUV(x,y, a0,a1,a2,a3, p0,p1,p2,p3); return uv; } @@ -1347,27 +1371,12 @@ static gp_UV CalcUV2(double x, double y, 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); - - double param_b = uv_eb[0].normParam + x * (uv_eb.back().normParam - uv_eb[0].normParam); - double param_t = uv_et[0].normParam + x * (uv_et.back().normParam - uv_et[0].normParam); - double param_r = uv_er[0].normParam + y * (uv_er.back().normParam - uv_er[0].normParam); - double param_l = uv_el[0].normParam + y * (uv_el.back().normParam - uv_el[0].normParam); - - gp_UV p0 = quad->side[BOTTOM_SIDE]->Value2d(param_b).XY(); - gp_UV p1 = quad->side[RIGHT_SIDE ]->Value2d(param_r).XY(); - gp_UV p2 = quad->side[TOP_SIDE ]->Value2d(param_t).XY(); - gp_UV p3 = quad->side[LEFT_SIDE ]->Value2d(param_l).XY(); + 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 uv = p0 * (1 - y) + p1 * x + p2 * y + p3 * (1 - x); - - uv -= (1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3; + gp_UV uv = CalcUV(x,y, a0,a1,a2,a3, p0,p1,p2,p3); return uv; } @@ -1387,20 +1396,14 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, // of meshing after implementation new variant // for bug 0016220 from Mantis. bool OldVersion = false; + if (myQuadType == QUAD_QUADRANGLE_PREF_REVERSED) + OldVersion = true; SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); const TopoDS_Face& F = TopoDS::Face(aShape); Handle(Geom_Surface) S = BRep_Tool::Surface(F); -// const TopoDS_Wire& W = BRepTools::OuterWire(F); bool WisF = true; -// if(W.Orientation()==TopAbs_FORWARD) -// WisF = true; - //if(WisF) cout<<"W is FORWARD"<ShapeToIndex( F ); + int i,j,geomFaceID = meshDS->ShapeToIndex(F); int nb = quad->side[0]->NbPoints(); int nr = quad->side[1]->NbPoints(); @@ -1409,8 +1412,8 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, int dh = abs(nb-nt); int dv = abs(nr-nl); - if( dh>=dv ) { - if( nt>nb ) { + if (dh>=dv) { + if (nt>nb) { // it is a base case => not shift quad but me be replacement is need ShiftQuad(quad,0,WisF); } @@ -1420,7 +1423,7 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, } } else { - if( nr>nl ) { + if (nr>nl) { // we have to shift quad on 1 ShiftQuad(quad,1,WisF); } @@ -1469,7 +1472,7 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, // 0------------0 // 0 bottom 1 - if(dh>dv) { + if (dh>dv) { addv = (dh-dv)/2; nbv = nbv + addv; } @@ -1478,82 +1481,81 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, nbh = nbh + addh; } - const vector& uv_eb = quad->side[0]->GetUVPtStruct(true,0 ); + 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_et = quad->side[2]->GetUVPtStruct(true,1); const vector& uv_el = quad->side[3]->GetUVPtStruct(false,0); - if ( uv_eb.size() != nb || uv_er.size() != nr || uv_et.size() != nt || uv_el.size() != nl ) - return error( COMPERR_BAD_INPUT_MESH ); + if (uv_eb.size() != nb || uv_er.size() != nr || uv_et.size() != nt || uv_el.size() != nl) + return error(COMPERR_BAD_INPUT_MESH); // arrays for normalized params //cout<<"Dump B:"<X()<<","<Y()<<","<Z()<<")"<0) { + if (dl>0) { // add top nodes - for(i=1; i<=dl; i++) + for (i=1; i<=dl; i++) NodesL.SetValue(i+1,nl,uv_et[i].node); // create and add needed nodes TColgp_SequenceOfXY UVtmp; - for(i=1; i<=dl; i++) { + for (i=1; i<=dl; i++) { double x0 = npt.Value(i+1); double x1 = x0; // diagonal node @@ -1564,9 +1566,9 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); NodesL.SetValue(i+1,1,N); - if(UVL.Length()AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); NodesL.SetValue(i+1,j,N); - if( i==dl ) UVtmp.Append(UV); + if (i==dl) UVtmp.Append(UV); } } - for(i=1; i<=UVtmp.Length() && UVL.Length()X()<<","<Y()<<","<Z()<<")"; // } // cout<AddFace(NodesL.Value(i,j), NodesL.Value(i+1,j), NodesL.Value(i+1,j+1), NodesL.Value(i,j+1)); - if(F) meshDS->SetMeshElementOnShape(F, geomFaceID); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); } else { SMDS_MeshFace* F = myTool->AddFace(NodesL.Value(i,j), NodesL.Value(i,j+1), NodesL.Value(i+1,j+1), NodesL.Value(i+1,j)); - if(F) meshDS->SetMeshElementOnShape(F, geomFaceID); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); } } } } else { // fill UVL using c2d - for(i=1; i0) { + if (dr>0) { // add top nodes - for(i=1; i<=dr; i++) + for (i=1; i<=dr; i++) NodesR.SetValue(i+1,1,uv_et[nt-1-i].node); // create and add needed nodes TColgp_SequenceOfXY UVtmp; - for(i=1; i<=dr; i++) { + for (i=1; i<=dr; i++) { double x0 = npt.Value(nt-i); double x1 = x0; // diagonal node @@ -1635,9 +1637,9 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); NodesR.SetValue(i+1,nr,N); - if(UVR.Length()AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); NodesR.SetValue(i+1,j,N); - if( i==dr ) UVtmp.Prepend(UV); + if (i==dr) UVtmp.Prepend(UV); } } - for(i=1; i<=UVtmp.Length() && UVR.Length()AddFace(NodesR.Value(i,j), NodesR.Value(i+1,j), NodesR.Value(i+1,j+1), NodesR.Value(i,j+1)); - if(F) meshDS->SetMeshElementOnShape(F, geomFaceID); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); } else { SMDS_MeshFace* F = myTool->AddFace(NodesR.Value(i,j), NodesR.Value(i,j+1), NodesR.Value(i+1,j+1), NodesR.Value(i+1,j)); - if(F) meshDS->SetMeshElementOnShape(F, geomFaceID); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); } } } } else { // fill UVR using c2d - for(i=1; iAddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); NodesC.SetValue(i,nbv-nnn+j,N); + if ( j==1 ) + UVT.Append( UV ); } } // add diagonal layers //cout<<"UVL.Length()="<Value(u,v); + gp_UV A2 = UVR.Value(nbv-nnn); + gp_UV A3 = UVL.Value(nbv-nnn); + for (i=1; iValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); - meshDS->SetNodeOnFace(N, geomFaceID, u, v); + meshDS->SetNodeOnFace(N, geomFaceID, UV.X(),UV.Y()); NodesC.SetValue(j,i+1,N); } } // create faces - for(i=1; iAddFace(NodesC.Value(i,j), NodesC.Value(i+1,j), NodesC.Value(i+1,j+1), NodesC.Value(i,j+1)); - if(F) meshDS->SetMeshElementOnShape(F, geomFaceID); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); } else { SMDS_MeshFace* F = myTool->AddFace(NodesC.Value(i,j), NodesC.Value(i,j+1), NodesC.Value(i+1,j+1), NodesC.Value(i+1,j)); - if(F) meshDS->SetMeshElementOnShape(F, geomFaceID); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); } } } @@ -1752,39 +1761,35 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, // step1: create faces for bottom rectangle domain StdMeshers_Array2OfNode NodesBRD(1,nb,1,nnn-1); // fill UVL and UVR using c2d - for(j=0; jValue(u,v); + for (j=2; jValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); - meshDS->SetNodeOnFace(N, geomFaceID, u, v); + meshDS->SetNodeOnFace(N, geomFaceID, UV.X(),UV.Y()); NodesBRD.SetValue(j,i+1,N); - } } - int nbf=0; - for(j=1; jAddFace(NodesBRD.Value(i,j), NodesBRD.Value(i+1,j), NodesBRD.Value(i+1,j+1), NodesBRD.Value(i,j+1)); - if(F) meshDS->SetMeshElementOnShape(F, geomFaceID); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); } else { SMDS_MeshFace* F = myTool->AddFace(NodesBRD.Value(i,j), NodesBRD.Value(i,j+1), NodesBRD.Value(i+1,j+1), NodesBRD.Value(i+1,j)); - if(F) meshDS->SetMeshElementOnShape(F, geomFaceID); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); } } } @@ -1792,19 +1797,19 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, // create faces for region C StdMeshers_Array2OfNode NodesC(1,nb,1,drl+1+addv); // add nodes from previous region - for(j=1; j<=nb; j++) { + for (j=1; j<=nb; j++) { NodesC.SetValue(j,1,NodesBRD.Value(j,nnn-1)); } - if( (drl+addv) > 0 ) { + if ((drl+addv) > 0) { int n1,n2; - if(nr>nl) { + if (nr>nl) { n1 = 1; n2 = drl + 1; TColgp_SequenceOfXY UVtmp; double drparam = npr.Value(nr) - npr.Value(nnn-1); double dlparam = npl.Value(nnn) - npl.Value(nnn-1); double y0,y1; - for(i=1; i<=drl; i++) { + for (i=1; i<=drl; i++) { // add existed nodes from right edge NodesC.SetValue(nb,i+1,uv_er[nnn+i-2].node); //double dtparam = npt.Value(i+1); @@ -1812,7 +1817,7 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, double dpar = (y1 - npr.Value(nnn-1))/drparam; y0 = npl.Value(nnn-1) + dpar*dlparam; // param on left edge double dy = y1 - y0; - for(j=1; jValue(UV.X(),UV.Y()); @@ -1848,14 +1853,14 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, double drparam = npr.Value(nnn) - npr.Value(nnn-1); double y0 = npl.Value(nnn-1); double y1 = npr.Value(nnn-1); - for(i=1; i<=drl; i++) { + for (i=1; i<=drl; i++) { // add existed nodes from right edge NodesC.SetValue(1,i+1,uv_el[nnn+i-2].node); y0 = npl.Value(nnn+i-1); // param on left edge double dpar = (y0 - npl.Value(nnn-1))/dlparam; y1 = npr.Value(nnn-1) + dpar*drparam; // param on right edge double dy = y1 - y0; - for(j=2; j<=nb; j++) { + 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); @@ -1867,13 +1872,13 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, } double dy0 = (1-y0)/(addv+1); double dy1 = (1-y1)/(addv+1); - for(i=1; i<=addv; i++) { + for (i=1; i<=addv; i++) { double yy0 = y0 + dy0*i; double yy1 = y1 + dy1*i; double dyy = yy1 - yy0; - for(j=1; j<=nb; j++) { + for (j=1; j<=nb; j++) { double x = npt.Value(i+1) + - npb.Value(j) * ( npt.Value(nt-i-drl) - 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_Pnt P = S->Value(UV.X(),UV.Y()); @@ -1884,57 +1889,55 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, } } // create faces - for(j=1; j<=drl+addv; j++) { - for(i=1; iAddFace(NodesC.Value(i,j), NodesC.Value(i+1,j), NodesC.Value(i+1,j+1), NodesC.Value(i,j+1)); - if(F) meshDS->SetMeshElementOnShape(F, geomFaceID); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); } else { SMDS_MeshFace* F = myTool->AddFace(NodesC.Value(i,j), NodesC.Value(i,j+1), NodesC.Value(i+1,j+1), NodesC.Value(i+1,j)); - if(F) meshDS->SetMeshElementOnShape(F, geomFaceID); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); } } } // end nr=n2; i--) { + for (i=drl+addv; i>=n2; i--) { nnn++; NodesLast.SetValue(nnn,1,NodesC.Value(nb,i)); } - for(i=1; iAddFace(NodesLast.Value(i,1), NodesLast.Value(i+1,1), NodesLast.Value(i+1,2), NodesLast.Value(i,2)); - if(F) meshDS->SetMeshElementOnShape(F, geomFaceID); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); } else { SMDS_MeshFace* F = myTool->AddFace(NodesLast.Value(i,1), NodesLast.Value(i,2), NodesLast.Value(i+1,2), NodesLast.Value(i+1,2)); - if(F) meshDS->SetMeshElementOnShape(F, geomFaceID); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); } } - } // if( (drl+addv) > 0 ) + } // if ((drl+addv) > 0) } // end new version implementation @@ -1959,6 +1962,8 @@ bool StdMeshers_Quadrangle_2D::EvaluateQuadPref(SMESH_Mesh & aMesh, // of meshing after implementation new variant // for bug 0016220 from Mantis. bool OldVersion = false; + if (myQuadType == QUAD_QUADRANGLE_PREF_REVERSED) + OldVersion = true; const TopoDS_Face& F = TopoDS::Face(aShape); Handle(Geom_Surface) S = BRep_Tool::Surface(F); @@ -1970,8 +1975,8 @@ bool StdMeshers_Quadrangle_2D::EvaluateQuadPref(SMESH_Mesh & aMesh, int dh = abs(nb-nt); int dv = abs(nr-nl); - if( dh>=dv ) { - if( nt>nb ) { + if (dh>=dv) { + if (nt>nb) { // it is a base case => not shift } else { @@ -1983,7 +1988,7 @@ bool StdMeshers_Quadrangle_2D::EvaluateQuadPref(SMESH_Mesh & aMesh, } } else { - if( nr>nl ) { + if (nr>nl) { // we have to shift quad on 1 nb = aNbNodes[3]; nr = aNbNodes[0]; @@ -2006,7 +2011,7 @@ bool StdMeshers_Quadrangle_2D::EvaluateQuadPref(SMESH_Mesh & aMesh, int addh = 0; int addv = 0; - if(dh>dv) { + if (dh>dv) { addv = (dh-dv)/2; nbv = nbv + addv; } @@ -2016,7 +2021,7 @@ bool StdMeshers_Quadrangle_2D::EvaluateQuadPref(SMESH_Mesh & aMesh, } int dl,dr; - if(OldVersion) { + if (OldVersion) { // add some params to right and left after the first param // insert to right dr = nbv - nr; @@ -2028,14 +2033,14 @@ bool StdMeshers_Quadrangle_2D::EvaluateQuadPref(SMESH_Mesh & aMesh, int nbNodes = 0; int nbFaces = 0; - if(OldVersion) { + if (OldVersion) { // step1: create faces for left domain - if(dl>0) { + if (dl>0) { nbNodes += dl*(nl-1); nbFaces += dl*(nl-1); } // step2: create faces for right domain - if(dr>0) { + if (dr>0) { nbNodes += dr*(nr-1); nbFaces += dr*(nr-1); } @@ -2052,11 +2057,11 @@ bool StdMeshers_Quadrangle_2D::EvaluateQuadPref(SMESH_Mesh & aMesh, } // end new version implementation std::vector aVec(SMDSEntity_Last); - for(int i=SMDSEntity_Node; iX(),theNode3->Y(),theNode3->Z()); gp_Pnt d(theNode4->X(),theNode4->Y(),theNode4->Z()); SMDS_MeshFace* face; - if(a.Distance(c) > b.Distance(d)){ + if (a.Distance(c) > b.Distance(d)){ face = myTool->AddFace(theNode2, theNode4 , theNode1); - if(face) theMeshDS->SetMeshElementOnShape(face, theFaceID ); + if (face) theMeshDS->SetMeshElementOnShape(face, theFaceID); face = myTool->AddFace(theNode2, theNode3, theNode4); - if(face) theMeshDS->SetMeshElementOnShape(face, theFaceID ); + if (face) theMeshDS->SetMeshElementOnShape(face, theFaceID); } else{ face = myTool->AddFace(theNode1, theNode2 ,theNode3); - if(face) theMeshDS->SetMeshElementOnShape(face, theFaceID ); + if (face) theMeshDS->SetMeshElementOnShape(face, theFaceID); face = myTool->AddFace(theNode1, theNode3, theNode4); - if(face) theMeshDS->SetMeshElementOnShape(face, theFaceID ); + if (face) theMeshDS->SetMeshElementOnShape(face, theFaceID); } } +//======================================================================= +/*! + * Implementation of Reduced algorithm (meshing with quadrangles only) + */ +//======================================================================= +bool StdMeshers_Quadrangle_2D::ComputeReduced (SMESH_Mesh & aMesh, + const TopoDS_Shape& aShape, + FaceQuadStruct* quad) +{ + SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); + const TopoDS_Face& F = TopoDS::Face(aShape); + Handle(Geom_Surface) S = BRep_Tool::Surface(F); + int i,j,geomFaceID = meshDS->ShapeToIndex(F); + + int nb = quad->side[0]->NbPoints(); + int nr = quad->side[1]->NbPoints(); + int nt = quad->side[2]->NbPoints(); + int nl = quad->side[3]->NbPoints(); + + // Simple Reduce 8->6->4->2 (3 steps) Multiple Reduce 8->2 (1 step) + // + // .-----.-----.-----.-----. .-----.-----.-----.-----. + // | / \ | / \ | | / \ | / \ | + // | / .--.--. \ | | / \ | / \ | + // | / / | \ \ | | / .----.----. \ | + // .---.---.---.---.---.---. | / / \ | / \ \ | + // | / / \ | / \ \ | | / / \ | / \ \ | + // | / / .-.-. \ \ | | / / .---.---. \ \ | + // | / / / | \ \ \ | | / / / \ | / \ \ \ | + // .--.--.--.--.--.--.--.--. | / / / \ | / \ \ \ | + // | / / / \ | / \ \ \ | | / / / .-.-. \ \ \ | + // | / / / .-.-. \ \ \ | | / / / / | \ \ \ \ | + // | / / / / | \ \ \ \ | | / / / / | \ \ \ \ | + // .-.-.-.--.--.--.--.-.-.-. .-.-.-.--.--.--.--.-.-.-. + + bool MultipleReduce = false; + { + int nb1 = nb; + int nr1 = nr; + int nt1 = nt; + int nl1 = nl; + + if (nr == nl) { + if (nb < nt) { + nt1 = nb; + nb1 = nt; + } + } + else if (nb == nt) { + nl1 = nb; // and == nt + nr1 = nb; // and == nt + if (nl < nr) { + nt1 = nl; + nb1 = nr; + } + else { + nt1 = nr; + nb1 = nl; + } + } + else { + return false; + } + + // number of rows and columns + int nrows = nr1 - 1; // and also == nl1 - 1 + int ncol_top = nt1 - 1; + int ncol_bot = nb1 - 1; + int npair_top = ncol_top / 2; + // maximum number of bottom elements for "linear" simple reduce + //int max_lin = ncol_top + npair_top * 2 * nrows; + // maximum number of bottom elements for "tree" simple reduce + int max_tree = npair_top * pow(2.0, nrows + 1); + if (ncol_top > npair_top * 2) { + int delta = ncol_bot - max_tree; + for (int irow = 1; irow < nrows; irow++) { + int nfour = delta / 4; + delta -= nfour*2; + } + if (delta <= (ncol_top - npair_top * 2)) + max_tree = ncol_bot; + } + + if (ncol_bot > max_tree) + MultipleReduce = true; + } + + if (MultipleReduce) { // == ComputeQuadPref QUAD_QUADRANGLE_PREF_REVERSED + //================================================== + int dh = abs(nb-nt); + int dv = abs(nr-nl); + + if (dh >= dv) { + if (nt > nb) { + // it is a base case => not shift quad but may be replacement is need + ShiftQuad(quad,0,true); + } + else { + // we have to shift quad on 2 + ShiftQuad(quad,2,true); + } + } + else { + if (nr > nl) { + // we have to shift quad on 1 + ShiftQuad(quad,1,true); + } + else { + // we have to shift quad on 3 + ShiftQuad(quad,3,true); + } + } + + nb = quad->side[0]->NbPoints(); + nr = quad->side[1]->NbPoints(); + nt = quad->side[2]->NbPoints(); + nl = quad->side[3]->NbPoints(); + dh = abs(nb-nt); + dv = abs(nr-nl); + int nbh = Max(nb,nt); + int nbv = Max(nr,nl); + int addh = 0; + int addv = 0; + + if (dh>dv) { + addv = (dh-dv)/2; + nbv = nbv + addv; + } + else { // dv>=dh + addh = (dv-dh)/2; + nbh = nbh + addh; + } + + 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); + + if (uv_eb.size() != nb || uv_er.size() != nr || uv_et.size() != nt || uv_el.size() != nl) + return error(COMPERR_BAD_INPUT_MESH); + + // arrays for normalized params + TColStd_SequenceOfReal npb, npr, npt, npl; + for (j = 0; j < nb; j++) { + npb.Append(uv_eb[j].normParam); + } + for (i = 0; i < nr; i++) { + npr.Append(uv_er[i].normParam); + } + for (j = 0; j < nt; j++) { + npt.Append(uv_et[j].normParam); + } + for (i = 0; i < nl; i++) { + npl.Append(uv_el[i].normParam); + } + + int dl,dr; + // orientation of face and 3 main domain for future faces + // 0 top 1 + // 1------------1 + // | | | | + // | | | | + // | L | | R | + // left | | | | rigth + // | / \ | + // | / C \ | + // |/ \| + // 0------------0 + // 0 bottom 1 + + // add some params to right and left after the first param + // insert to right + dr = nbv - nr; + double dpr = (npr.Value(2) - npr.Value(1))/(dr+1); + for (i=1; i<=dr; i++) { + npr.InsertAfter(1,npr.Value(2)-dpr); + } + // insert to left + dl = nbv - nl; + dpr = (npl.Value(2) - npl.Value(1))/(dl+1); + for (i=1; i<=dl; i++) { + npl.InsertAfter(1,npl.Value(2)-dpr); + } + + gp_XY a0 (uv_eb.front().u, uv_eb.front().v); + gp_XY a1 (uv_eb.back().u, uv_eb.back().v); + gp_XY a2 (uv_et.back().u, uv_et.back().v); + gp_XY a3 (uv_et.front().u, uv_et.front().v); + + int nnn = Min(nr,nl); + // auxilary sequence of XY for creation nodes + // in the bottom part of central domain + // it's length must be == nbv-nnn-1 + TColgp_SequenceOfXY UVL; + TColgp_SequenceOfXY UVR; + //================================================== + + // step1: create faces for left domain + StdMeshers_Array2OfNode NodesL(1,dl+1,1,nl); + // add left nodes + for (j=1; j<=nl; j++) + NodesL.SetValue(1,j,uv_el[j-1].node); + if (dl>0) { + // add top nodes + for (i=1; i<=dl; i++) + NodesL.SetValue(i+1,nl,uv_et[i].node); + // create and add needed nodes + TColgp_SequenceOfXY UVtmp; + for (i=1; i<=dl; i++) { + double x0 = npt.Value(i+1); + double x1 = x0; + // 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_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()); + NodesL.SetValue(i+1,1,N); + if (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()); + NodesL.SetValue(i+1,j,N); + if (i==dl) UVtmp.Append(UV); + } + } + for (i=1; i<=UVtmp.Length() && UVL.Length()AddFace(NodesL.Value(i,j), NodesL.Value(i+1,j), + NodesL.Value(i+1,j+1), NodesL.Value(i,j+1)); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); + } + } + } + else { + // fill UVL using c2d + for (i=1; i0) { + // add top nodes + for (i=1; i<=dr; i++) + NodesR.SetValue(i+1,1,uv_et[nt-1-i].node); + // create and add needed nodes + TColgp_SequenceOfXY UVtmp; + for (i=1; i<=dr; i++) { + double x0 = npt.Value(nt-i); + double x1 = x0; + // 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_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()); + NodesR.SetValue(i+1,nr,N); + if (UVR.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()); + NodesR.SetValue(i+1,j,N); + if (i==dr) UVtmp.Prepend(UV); + } + } + for (i=1; i<=UVtmp.Length() && UVR.Length()AddFace(NodesR.Value(i,j), NodesR.Value(i+1,j), + NodesR.Value(i+1,j+1), NodesR.Value(i,j+1)); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); + } + } + } + else { + // fill UVR using c2d + for (i=1; iValue(UV.X(),UV.Y()); + SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); + NodesC.SetValue(i,nbv-nnn+j,N); + } + } + // add diagonal layers + for (i=1; iValue(u,v); + SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(N, geomFaceID, u, v); + NodesC.SetValue(j,i+1,N); + } + } + // create faces + for (i=1; iAddFace(NodesC.Value(i,j), NodesC.Value(i+1,j), + NodesC.Value(i+1,j+1), NodesC.Value(i,j+1)); + if (F) meshDS->SetMeshElementOnShape(F, geomFaceID); + } + } + // TODO ??? + } // end Multiple Reduce implementation + else { // Simple Reduce (!MultipleReduce) + //========================================================= + if (nr == nl) { + if (nt < nb) { + // it is a base case => not shift quad + //ShiftQuad(quad,0,true); + } + else { + // we have to shift quad on 2 + ShiftQuad(quad,2,true); + } + } + else { + if (nl > nr) { + // we have to shift quad on 1 + ShiftQuad(quad,1,true); + } + else { + // we have to shift quad on 3 + ShiftQuad(quad,3,true); + } + } + + nb = quad->side[0]->NbPoints(); + nr = quad->side[1]->NbPoints(); + nt = quad->side[2]->NbPoints(); + nl = quad->side[3]->NbPoints(); + + // number of rows and columns + int nrows = nr - 1; // and also == nl - 1 + int ncol_top = nt - 1; + int ncol_bot = nb - 1; + int npair_top = ncol_top / 2; + // maximum number of bottom elements for "linear" simple reduce + int max_lin = ncol_top + npair_top * 2 * nrows; + // maximum number of bottom elements for "tree" simple reduce + //int max_tree = npair_top * pow(2, nrows + 1); + + //if (ncol_bot > max_tree) + // MultipleReduce = true; + + 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); + + if (uv_eb.size() != nb || uv_er.size() != nr || uv_et.size() != nt || uv_el.size() != nl) + return error(COMPERR_BAD_INPUT_MESH); + + // arrays for normalized params + TColStd_SequenceOfReal npb, npr, npt, npl; + for (j = 0; j < nb; j++) { + npb.Append(uv_eb[j].normParam); + } + for (i = 0; i < nr; i++) { + npr.Append(uv_er[i].normParam); + } + for (j = 0; j < nt; j++) { + npt.Append(uv_et[j].normParam); + } + for (i = 0; i < nl; i++) { + npl.Append(uv_el[i].normParam); + } + + // We will ajust new points to this grid + if (!SetNormalizedGrid(aMesh, aShape, quad)) + return false; + + // TODO ??? + gp_XY a0 (uv_eb.front().u, uv_eb.front().v); + gp_XY a1 (uv_eb.back().u, uv_eb.back().v); + gp_XY a2 (uv_et.back().u, uv_et.back().v); + gp_XY a3 (uv_et.front().u, uv_et.front().v); + //========================================================= + + TColStd_SequenceOfInteger curr_base, next_base; + TColStd_SequenceOfReal curr_par_u, curr_par_v; + TColStd_SequenceOfReal next_par_u, next_par_v; + StdMeshers_Array2OfNode NodesBRD (1,nb, 1,nr); + for (j = 1; j <= nb; j++) { + NodesBRD.SetValue(j, 1, uv_eb[j - 1].node); // bottom + curr_base.Append(j); + next_base.Append(-1); + curr_par_u.Append(uv_eb[j-1].u); + curr_par_v.Append(uv_eb[j-1].v); + next_par_u.Append(0.); + next_par_v.Append(0.); + } + for (j = 1; j <= nt; j++) { + NodesBRD.SetValue(j, nr, uv_et[j - 1].node); // top + } + + int curr_base_len = nb; + int next_base_len = 0; + + if (ncol_bot > max_lin) { + // "tree" simple reduce 2->4->8->16->32->... + // + // .---------------.---------------.---------------.---------------. nr + // | \ | / | \ | / | + // | \ .-------.-------. / | \ .-------.-------. / | + // | | | | | | | | | + // .-------.-------.-------.-------.-------.-------.-------.-------. + // |\ | /|\ | /|\ | /|\ | /| + // | \.---.---./ | \.---.---./ | \.---.---./ | \.---.---./ | i + // | | | | | | | | | | | | | | | | | + // .---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. + // |\ | /|\ | /|\ | /|\ | /|\ | /|\ | /|\ | /|\ | /| + // | .-.-. | .-.-. | .-.-. | .-.-. | .-.-. | .-.-. | .-.-. | .-.-. | + // | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + // .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. 1 + // 1 j nb + + for (i = 1; i < nr; i++) { // layer by layer + // left + NodesBRD.SetValue(1, i+1, uv_el[i].node); + next_base.SetValue(++next_base_len, 1); + // right + NodesBRD.SetValue(nb, i+1, uv_er[i].node); + + next_par_u.SetValue(next_base_len, uv_el[i].u); + next_par_v.SetValue(next_base_len, uv_el[i].v); + + // to stop reducing, if number of nodes reaches nt + int delta = curr_base_len - nt; + + //double du = uv_er[i].u - uv_el[i].u; + //double dv = uv_er[i].v - uv_el[i].v; + + // to calculate normalized parameter, we must know number of points in next layer + int nb_four = (curr_base_len - 1) / 4; + int nb_next = nb_four*2 + (curr_base_len - nb_four*4); + if (nb_next < nt) nb_next = nt; + + for (j = 1; j + 4 <= curr_base_len && delta > 0; j += 4, delta -= 2) { + // add one "HH": nodes a,b,c,d,e and faces 1,2,3,4,5,6 + // + // .-----a-----b i + 1 + // |\ 5 | 6 /| + // | \ | / | + // | c--d--e | + // |1 |2 |3 |4 | + // | | | | | + // .--.--.--.--. i + // + // j j+2 j+4 + + double u,v; + + // a (i + 1, j + 2) + const SMDS_MeshNode* Na; + next_base_len++; + next_base.SetValue(next_base_len, curr_base.Value(j + 2)); + if (i + 1 == nr) { // top + Na = uv_et[next_base_len - 1].node; + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Na); + u = uv_et[next_base_len - 1].u; + v = uv_et[next_base_len - 1].v; + } + else { + //double norm_par = double(next_base_len - 1)/double(nb_next - 1); + //u = uv_el[i].u + du * norm_par; + //v = uv_el[i].v + dv * norm_par; + { + double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1; + int nearest_node_j = (int)rel; + rel -= nearest_node_j; + int ij = (i + 1 - 1) * nt + (nearest_node_j - 1); + double u1 = quad->uv_grid[ij].u; + double v1 = quad->uv_grid[ij].v; + double u2 = quad->uv_grid[ij + 1].u; + double v2 = quad->uv_grid[ij + 1].v; + double duj = (u2 - u1) * rel; + double dvj = (v2 - v1) * rel; + u = u1 + duj; + v = v1 + dvj; + } + //u = uv_el[i].u + du*npb.Value(curr_base.Value(j + 2)); + //v = uv_el[i].v + dv*npb.Value(curr_base.Value(j + 2)); + gp_Pnt P = S->Value(u,v); + SMDS_MeshNode* Na1 = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Na1, geomFaceID, u, v); + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Na1); + Na = Na1; + } + next_par_u.SetValue(next_base_len, u); + next_par_v.SetValue(next_base_len, v); + + // b (i + 1, j + 4) + const SMDS_MeshNode* Nb; + next_base_len++; + next_base.SetValue(next_base_len, curr_base.Value(j + 4)); + if (i + 1 == nr) { // top + Nb = uv_et[next_base_len - 1].node; + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nb); + u = uv_et[next_base_len - 1].u; + v = uv_et[next_base_len - 1].v; + } + else if (j + 4 == curr_base_len) { // right + Nb = NodesBRD.Value(next_base.Value(next_base_len), i + 1); + u = uv_er[i].u; + v = uv_er[i].v; + } + else { + //double norm_par = double(next_base_len - 1)/double(nb_next - 1); + //u = uv_el[i].u + du * norm_par; + //v = uv_el[i].v + dv * norm_par; + { + double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1; + int nearest_node_j = (int)rel; + rel -= nearest_node_j; + int ij = (i + 1 - 1) * nt + (nearest_node_j - 1); + double u1 = quad->uv_grid[ij].u; + double v1 = quad->uv_grid[ij].v; + double u2 = quad->uv_grid[ij + 1].u; + double v2 = quad->uv_grid[ij + 1].v; + double duj = (u2 - u1) * rel; + double dvj = (v2 - v1) * rel; + u = u1 + duj; + v = v1 + dvj; + } + //u = uv_el[i].u + du*npb.Value(curr_base.Value(j + 4)); + //v = uv_el[i].v + dv*npb.Value(curr_base.Value(j + 4)); + gp_Pnt P = S->Value(u,v); + SMDS_MeshNode* Nb1 = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Nb1, geomFaceID, u, v); + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nb1); + Nb = Nb1; + } + next_par_u.SetValue(next_base_len, u); + next_par_v.SetValue(next_base_len, v); + + // c + u = (curr_par_u.Value(j + 2) + next_par_u.Value(next_base_len - 2)) / 2.0; + v = (curr_par_v.Value(j + 2) + next_par_v.Value(next_base_len - 2)) / 2.0; + gp_Pnt P = S->Value(u,v); + SMDS_MeshNode* Nc = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Nc, geomFaceID, u, v); + + // d + u = (curr_par_u.Value(j + 2) + next_par_u.Value(next_base_len - 1)) / 2.0; + v = (curr_par_v.Value(j + 2) + next_par_v.Value(next_base_len - 1)) / 2.0; + P = S->Value(u,v); + SMDS_MeshNode* Nd = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Nd, geomFaceID, u, v); + + // e + u = (curr_par_u.Value(j + 2) + next_par_u.Value(next_base_len)) / 2.0; + v = (curr_par_v.Value(j + 2) + next_par_v.Value(next_base_len)) / 2.0; + P = S->Value(u,v); + SMDS_MeshNode* Ne = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Ne, geomFaceID, u, v); + + // Faces + SMDS_MeshFace* F1 = myTool->AddFace(NodesBRD.Value(curr_base.Value(j + 0), i), + NodesBRD.Value(curr_base.Value(j + 1), i), + Nc, + NodesBRD.Value(next_base.Value(next_base_len - 2), i + 1)); + if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID); + + SMDS_MeshFace* F2 = myTool->AddFace(NodesBRD.Value(curr_base.Value(j + 1), i), + NodesBRD.Value(curr_base.Value(j + 2), i), + Nd, Nc); + if (F2) meshDS->SetMeshElementOnShape(F2, geomFaceID); + + SMDS_MeshFace* F3 = myTool->AddFace(NodesBRD.Value(curr_base.Value(j + 2), i), + NodesBRD.Value(curr_base.Value(j + 3), i), + Ne, Nd); + if (F3) meshDS->SetMeshElementOnShape(F3, geomFaceID); + + SMDS_MeshFace* F4 = myTool->AddFace(NodesBRD.Value(curr_base.Value(j + 3), i), + NodesBRD.Value(curr_base.Value(j + 4), i), + Nb, Ne); + if (F4) meshDS->SetMeshElementOnShape(F4, geomFaceID); + + SMDS_MeshFace* F5 = myTool->AddFace(Nc, Nd, Na, + NodesBRD.Value(next_base.Value(next_base_len - 2), i + 1)); + if (F5) meshDS->SetMeshElementOnShape(F5, geomFaceID); + + SMDS_MeshFace* F6 = myTool->AddFace(Nd, Ne, Nb, Na); + if (F6) meshDS->SetMeshElementOnShape(F6, geomFaceID); + } + + // not reduced side elements (if any) + for (; j < curr_base_len; j++) { + // f (i + 1, j + 1) + const SMDS_MeshNode* Nf; + double u,v; + next_base.SetValue(++next_base_len, curr_base.Value(j + 1)); + if (i + 1 == nr) { // top + Nf = uv_et[next_base_len - 1].node; + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf); + u = uv_et[next_base_len - 1].u; + v = uv_et[next_base_len - 1].v; + } + else if (j + 1 == curr_base_len) { // right + Nf = NodesBRD.Value(next_base.Value(next_base_len), i + 1); + u = uv_er[i].u; + v = uv_er[i].v; + } + else { + //double norm_par = double(next_base_len - 1)/double(nb_next - 1); + //u = uv_el[i].u + du * norm_par; + //v = uv_el[i].v + dv * norm_par; + { + double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1; + int nearest_node_j = (int)rel; + rel -= nearest_node_j; + int ij = (i + 1 - 1) * nt + (nearest_node_j - 1); + double u1 = quad->uv_grid[ij].u; + double v1 = quad->uv_grid[ij].v; + double u2 = quad->uv_grid[ij + 1].u; + double v2 = quad->uv_grid[ij + 1].v; + double duj = (u2 - u1) * rel; + double dvj = (v2 - v1) * rel; + u = u1 + duj; + v = v1 + dvj; + } + //u = uv_el[i].u + du*npb.Value(curr_base.Value(j + 1)); + //v = uv_el[i].v + dv*npb.Value(curr_base.Value(j + 1)); + gp_Pnt P = S->Value(u,v); + SMDS_MeshNode* Nf1 = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Nf1, geomFaceID, u, v); + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf1); + Nf = Nf1; + } + next_par_u.SetValue(next_base_len, u); + next_par_v.SetValue(next_base_len, v); + SMDS_MeshFace* F1 = myTool->AddFace(NodesBRD.Value(curr_base.Value(j), i), + NodesBRD.Value(curr_base.Value(j + 1), i), + NodesBRD.Value(next_base.Value(next_base_len), i + 1), + NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1)); + if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID); + } + curr_base_len = next_base_len; + curr_base = next_base; + curr_par_u = next_par_u; + curr_par_v = next_par_v; + next_base_len = 0; + } + } // end "tree" simple reduce + else { + // "linear" simple reduce 4->8->12->16 (3 steps) + // + // .---------------.---------------.---------------.---------------. nr + // | \ | / | \ | / | + // | \ .-------.-------. / | \ .-------.-------. / | + // | | | | | | | | | + // .-------.-------.-------.-------.-------.-------.-------.-------. + // | / \ | / \ | / \ | / \ | + // | / \.----.----./ \ | / \.----.----./ \ | i + // | / | | | \ | / | | | \ | + // .-----.----.----.----.----.-----.-----.----.----.----.----.-----. + // | / / \ | / \ \ | / / \ | / \ \ | + // | / / .-.-. \ \ | / / .-.-. \ \ | + // | / / / | \ \ \ | / / / | \ \ \ | + // .---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. 1 + // 1 j nb + + // nt = 5, nb = 7, nr = 4 + //int delta_all = 2; + //int delta_one_col = 6; + //int nb_col = 0; + //int remainder = 2; + //if (remainder > 0) nb_col++; + //nb_col = 1; + //int free_left = 1; + //free_left += 2; + //int free_middle = 4; + + int delta_all = nb - nt; + int delta_one_col = (nr - 1) * 2; + int nb_col = delta_all / delta_one_col; + int remainder = delta_all - nb_col * delta_one_col; + if (remainder > 0) { + nb_col++; + } + int free_left = ((nt - 1) - nb_col * 2) / 2; + free_left += nr - 2; + int free_middle = (nr - 2) * 2; + if (remainder > 0 && nb_col == 1) { + int nb_rows_short_col = remainder / 2; + int nb_rows_thrown = (nr - 1) - nb_rows_short_col; + free_left -= nb_rows_thrown; + } + + // nt = 5, nb = 17, nr = 4 + //int delta_all = 12; + //int delta_one_col = 6; + //int nb_col = 2; + //int remainder = 0; + //int free_left = 2; + //int free_middle = 4; + + for (i = 1; i < nr; i++, free_middle -= 2, free_left -= 1) { // layer by layer + // left + NodesBRD.SetValue(1, i+1, uv_el[i].node); + next_base.SetValue(++next_base_len, 1); + // right + NodesBRD.SetValue(nb, i+1, uv_er[i].node); + + // left + next_par_u.SetValue(next_base_len, uv_el[i].u); + next_par_v.SetValue(next_base_len, uv_el[i].v); + + // to calculate normalized parameter, we must know number of points in next layer + int nb_next = curr_base_len - nb_col * 2; + if (remainder > 0 && i > remainder / 2) + // take into account short "column" + nb_next += 2; + if (nb_next < nt) nb_next = nt; + + // not reduced left elements + for (j = 1; j <= free_left; j++) { + // f (i + 1, j + 1) + const SMDS_MeshNode* Nf; + double u,v; + next_base.SetValue(++next_base_len, curr_base.Value(j + 1)); + if (i + 1 == nr) { // top + Nf = uv_et[next_base_len - 1].node; + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf); + u = uv_et[next_base_len - 1].u; + v = uv_et[next_base_len - 1].v; + } + else { + { + double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1; + int nearest_node_j = (int)rel; + rel -= nearest_node_j; + int ij = (i + 1 - 1) * nt + (nearest_node_j - 1); + double u1 = quad->uv_grid[ij].u; + double v1 = quad->uv_grid[ij].v; + double u2 = quad->uv_grid[ij + 1].u; + double v2 = quad->uv_grid[ij + 1].v; + double duj = (u2 - u1) * rel; + double dvj = (v2 - v1) * rel; + u = u1 + duj; + v = v1 + dvj; + } + gp_Pnt P = S->Value(u,v); + SMDS_MeshNode* Nf1 = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Nf1, geomFaceID, u, v); + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf1); + Nf = Nf1; + } + next_par_u.SetValue(next_base_len, u); + next_par_v.SetValue(next_base_len, v); + SMDS_MeshFace* F1 = myTool->AddFace(NodesBRD.Value(curr_base.Value(j), i), + NodesBRD.Value(curr_base.Value(j + 1), i), + NodesBRD.Value(next_base.Value(next_base_len), i + 1), + NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1)); + if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID); + } + + for (int icol = 1; icol <= nb_col; icol++) { + + if (remainder > 0 && icol == nb_col && i > remainder / 2) + // stop short "column" + break; + + // add one "HH": nodes a,b,c,d,e and faces 1,2,3,4,5,6 + // + // .-----a-----b i + 1 + // |\ 5 | 6 /| + // | \ | / | + // | c--d--e | + // |1 |2 |3 |4 | + // | | | | | + // .--.--.--.--. i + // + // j j+2 j+4 + + double u,v; + + // a (i + 1, j + 2) + const SMDS_MeshNode* Na; + next_base_len++; + next_base.SetValue(next_base_len, curr_base.Value(j + 2)); + if (i + 1 == nr) { // top + Na = uv_et[next_base_len - 1].node; + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Na); + u = uv_et[next_base_len - 1].u; + v = uv_et[next_base_len - 1].v; + } + else { + { + double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1; + int nearest_node_j = (int)rel; + rel -= nearest_node_j; + int ij = (i + 1 - 1) * nt + (nearest_node_j - 1); + double u1 = quad->uv_grid[ij].u; + double v1 = quad->uv_grid[ij].v; + double u2 = quad->uv_grid[ij + 1].u; + double v2 = quad->uv_grid[ij + 1].v; + double duj = (u2 - u1) * rel; + double dvj = (v2 - v1) * rel; + u = u1 + duj; + v = v1 + dvj; + } + gp_Pnt P = S->Value(u,v); + SMDS_MeshNode* Na1 = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Na1, geomFaceID, u, v); + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Na1); + Na = Na1; + } + next_par_u.SetValue(next_base_len, u); + next_par_v.SetValue(next_base_len, v); + + // b (i + 1, j + 4) + const SMDS_MeshNode* Nb; + next_base_len++; + next_base.SetValue(next_base_len, curr_base.Value(j + 4)); + if (i + 1 == nr) { // top + Nb = uv_et[next_base_len - 1].node; + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nb); + u = uv_et[next_base_len - 1].u; + v = uv_et[next_base_len - 1].v; + } + else if (j + 4 == curr_base_len) { // right + Nb = NodesBRD.Value(next_base.Value(next_base_len), i + 1); + u = uv_er[i].u; + v = uv_er[i].v; + } + else { + { + double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1; + int nearest_node_j = (int)rel; + rel -= nearest_node_j; + int ij = (i + 1 - 1) * nt + (nearest_node_j - 1); + double u1 = quad->uv_grid[ij].u; + double v1 = quad->uv_grid[ij].v; + double u2 = quad->uv_grid[ij + 1].u; + double v2 = quad->uv_grid[ij + 1].v; + double duj = (u2 - u1) * rel; + double dvj = (v2 - v1) * rel; + u = u1 + duj; + v = v1 + dvj; + } + gp_Pnt P = S->Value(u,v); + SMDS_MeshNode* Nb1 = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Nb1, geomFaceID, u, v); + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nb1); + Nb = Nb1; + } + next_par_u.SetValue(next_base_len, u); + next_par_v.SetValue(next_base_len, v); + + // c + u = (curr_par_u.Value(j + 2) + next_par_u.Value(next_base_len - 2)) / 2.0; + v = (curr_par_v.Value(j + 2) + next_par_v.Value(next_base_len - 2)) / 2.0; + gp_Pnt P = S->Value(u,v); + SMDS_MeshNode* Nc = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Nc, geomFaceID, u, v); + + // d + u = (curr_par_u.Value(j + 2) + next_par_u.Value(next_base_len - 1)) / 2.0; + v = (curr_par_v.Value(j + 2) + next_par_v.Value(next_base_len - 1)) / 2.0; + P = S->Value(u,v); + SMDS_MeshNode* Nd = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Nd, geomFaceID, u, v); + + // e + u = (curr_par_u.Value(j + 2) + next_par_u.Value(next_base_len)) / 2.0; + v = (curr_par_v.Value(j + 2) + next_par_v.Value(next_base_len)) / 2.0; + P = S->Value(u,v); + SMDS_MeshNode* Ne = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Ne, geomFaceID, u, v); + + // Faces + SMDS_MeshFace* F1 = myTool->AddFace(NodesBRD.Value(curr_base.Value(j + 0), i), + NodesBRD.Value(curr_base.Value(j + 1), i), + Nc, + NodesBRD.Value(next_base.Value(next_base_len - 2), i + 1)); + if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID); + + SMDS_MeshFace* F2 = myTool->AddFace(NodesBRD.Value(curr_base.Value(j + 1), i), + NodesBRD.Value(curr_base.Value(j + 2), i), + Nd, Nc); + if (F2) meshDS->SetMeshElementOnShape(F2, geomFaceID); + + SMDS_MeshFace* F3 = myTool->AddFace(NodesBRD.Value(curr_base.Value(j + 2), i), + NodesBRD.Value(curr_base.Value(j + 3), i), + Ne, Nd); + if (F3) meshDS->SetMeshElementOnShape(F3, geomFaceID); + + SMDS_MeshFace* F4 = myTool->AddFace(NodesBRD.Value(curr_base.Value(j + 3), i), + NodesBRD.Value(curr_base.Value(j + 4), i), + Nb, Ne); + if (F4) meshDS->SetMeshElementOnShape(F4, geomFaceID); + + SMDS_MeshFace* F5 = myTool->AddFace(Nc, Nd, Na, + NodesBRD.Value(next_base.Value(next_base_len - 2), i + 1)); + if (F5) meshDS->SetMeshElementOnShape(F5, geomFaceID); + + SMDS_MeshFace* F6 = myTool->AddFace(Nd, Ne, Nb, Na); + if (F6) meshDS->SetMeshElementOnShape(F6, geomFaceID); + + j += 4; + + // not reduced middle elements + if (icol < nb_col) { + if (remainder > 0 && icol == nb_col - 1 && i > remainder / 2) + // pass middle elements before stopped short "column" + break; + + int free_add = free_middle; + if (remainder > 0 && icol == nb_col - 1) + // next "column" is short + free_add -= (nr - 1) - (remainder / 2); + + for (int imiddle = 1; imiddle <= free_add; imiddle++) { + // f (i + 1, j + imiddle) + const SMDS_MeshNode* Nf; + double u,v; + next_base.SetValue(++next_base_len, curr_base.Value(j + imiddle)); + if (i + 1 == nr) { // top + Nf = uv_et[next_base_len - 1].node; + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf); + u = uv_et[next_base_len - 1].u; + v = uv_et[next_base_len - 1].v; + } + else if (j + imiddle == curr_base_len) { // right + Nf = NodesBRD.Value(next_base.Value(next_base_len), i + 1); + u = uv_er[i].u; + v = uv_er[i].v; + } + else { + { + double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1; + int nearest_node_j = (int)rel; + rel -= nearest_node_j; + int ij = (i + 1 - 1) * nt + (nearest_node_j - 1); + double u1 = quad->uv_grid[ij].u; + double v1 = quad->uv_grid[ij].v; + double u2 = quad->uv_grid[ij + 1].u; + double v2 = quad->uv_grid[ij + 1].v; + double duj = (u2 - u1) * rel; + double dvj = (v2 - v1) * rel; + u = u1 + duj; + v = v1 + dvj; + } + gp_Pnt P = S->Value(u,v); + SMDS_MeshNode* Nf1 = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Nf1, geomFaceID, u, v); + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf1); + Nf = Nf1; + } + next_par_u.SetValue(next_base_len, u); + next_par_v.SetValue(next_base_len, v); + SMDS_MeshFace* F1 = myTool->AddFace(NodesBRD.Value(curr_base.Value(j - 1 + imiddle), i), + NodesBRD.Value(curr_base.Value(j + imiddle), i), + NodesBRD.Value(next_base.Value(next_base_len), i + 1), + NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1)); + if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID); + } + j += free_add; + } + } + + // not reduced right elements + for (; j < curr_base_len; j++) { + // f (i + 1, j + 1) + const SMDS_MeshNode* Nf; + double u,v; + next_base.SetValue(++next_base_len, curr_base.Value(j + 1)); + if (i + 1 == nr) { // top + Nf = uv_et[next_base_len - 1].node; + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf); + u = uv_et[next_base_len - 1].u; + v = uv_et[next_base_len - 1].v; + } + else if (j + 1 == curr_base_len) { // right + Nf = NodesBRD.Value(next_base.Value(next_base_len), i + 1); + u = uv_er[i].u; + v = uv_er[i].v; + } + else { + { + double rel = double(next_base_len - 1) * double(nt - 1) / double(nb_next - 1) + 1; + int nearest_node_j = (int)rel; + rel -= nearest_node_j; + int ij = (i + 1 - 1) * nt + (nearest_node_j - 1); + double u1 = quad->uv_grid[ij].u; + double v1 = quad->uv_grid[ij].v; + double u2 = quad->uv_grid[ij + 1].u; + double v2 = quad->uv_grid[ij + 1].v; + double duj = (u2 - u1) * rel; + double dvj = (v2 - v1) * rel; + u = u1 + duj; + v = v1 + dvj; + } + gp_Pnt P = S->Value(u,v); + SMDS_MeshNode* Nf1 = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnFace(Nf1, geomFaceID, u, v); + NodesBRD.SetValue(next_base.Value(next_base_len), i + 1, Nf1); + Nf = Nf1; + } + next_par_u.SetValue(next_base_len, u); + next_par_v.SetValue(next_base_len, v); + SMDS_MeshFace* F1 = myTool->AddFace(NodesBRD.Value(curr_base.Value(j), i), + NodesBRD.Value(curr_base.Value(j + 1), i), + NodesBRD.Value(next_base.Value(next_base_len), i + 1), + NodesBRD.Value(next_base.Value(next_base_len - 1), i + 1)); + if (F1) meshDS->SetMeshElementOnShape(F1, geomFaceID); + } + + curr_base_len = next_base_len; + curr_base = next_base; + curr_par_u = next_par_u; + curr_par_v = next_par_v; + next_base_len = 0; + } + } // end "linear" simple reduce + } // end Simple Reduce implementation + + bool isOk = true; + return isOk; +} diff --git a/src/StdMeshers/StdMeshers_Quadrangle_2D.hxx b/src/StdMeshers/StdMeshers_Quadrangle_2D.hxx index 74c64f6f0..56741ec76 100644 --- a/src/StdMeshers/StdMeshers_Quadrangle_2D.hxx +++ b/src/StdMeshers/StdMeshers_Quadrangle_2D.hxx @@ -19,19 +19,20 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // - // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Quadrangle_2D.hxx // Moved here from SMESH_Quadrangle_2D.hxx // Author : Paul RASCLE, EDF // Module : SMESH // $Header$ -// + #ifndef _SMESH_QUADRANGLE_2D_HXX_ #define _SMESH_QUADRANGLE_2D_HXX_ #include "SMESH_StdMeshers.hxx" +#include "StdMeshers_QuadrangleParams.hxx" + #include "SMESH_2D_Algo.hxx" #include "Utils_SALOME_Exception.hxx" @@ -120,6 +121,10 @@ protected: const TopoDS_Face& F, const TopoDS_Edge& E, double first, double last, int nb_segm); + bool ComputeReduced (SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + FaceQuadStruct* quad); + // true if QuadranglePreference hypothesis is assigned that forces // construction of quadrangles if the number of nodes on opposite edges // is not the same in the case where the global number of nodes on edges @@ -130,6 +135,8 @@ protected: int myTriaVertexID; + StdMeshers_QuadType myQuadType; + SMESH_MesherHelper* myTool; // tool for working with quadratic elements }; diff --git a/src/StdMeshers/StdMeshers_RadialQuadrangle_1D2D.cxx b/src/StdMeshers/StdMeshers_RadialQuadrangle_1D2D.cxx index d03470fb3..cbf6f5692 100644 --- a/src/StdMeshers/StdMeshers_RadialQuadrangle_1D2D.cxx +++ b/src/StdMeshers/StdMeshers_RadialQuadrangle_1D2D.cxx @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -570,6 +571,8 @@ bool StdMeshers_RadialQuadrangle_1D2D::Compute(SMESH_Mesh& aMesh, if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge1,true,theNodes)) return error("Invalid mesh on a straight edge"); + Nodes1.resize( myLayerPositions.size()+1 ); + Nodes2.resize( myLayerPositions.size()+1 ); vector< const SMDS_MeshNode* > *pNodes1 = &Nodes1, *pNodes2 = &Nodes2; bool nodesFromP0ToP1 = ( theNodes.rbegin()->second == NF ); if ( !nodesFromP0ToP1 ) std::swap( pNodes1, pNodes2 ); @@ -580,8 +583,8 @@ bool StdMeshers_RadialQuadrangle_1D2D::Compute(SMESH_Mesh& aMesh, { (*pNodes1)[i] = ritn->second; (*pNodes2)[i] = itn->second; - Points.Append( gpXYZ( Nodes1[i])); - Pnts2d1.Append( myHelper->GetNodeUV( F, Nodes1[i])); + Points.Prepend( gpXYZ( Nodes1[i])); + Pnts2d1.Prepend( myHelper->GetNodeUV( F, Nodes1[i])); } NC = const_cast( itn->second ); Points.Remove( Nodes1.size() ); @@ -1030,9 +1033,25 @@ bool StdMeshers_RadialQuadrangle_1D2D::computeLayerPositions(const gp_Pnt& vector< double > nodeParams; GetNodeParamOnEdge( mesh->GetMeshDS(), linEdge, nodeParams ); + // nb of present nodes must be different in cases of 1 and 2 straight edges + + TopoDS_Vertex VV[2]; + TopExp::Vertices( linEdge, VV[0], VV[1]); + const gp_Pnt* points[] = { &p1, &p2 }; + gp_Pnt vPoints[] = { BRep_Tool::Pnt(VV[0]), BRep_Tool::Pnt(VV[1]) }; + const double tol[] = { BRep_Tool::Tolerance(VV[0]), BRep_Tool::Tolerance(VV[1]) }; + bool pointsAreOnVertices = true; + for ( int iP = 0; iP < 2 && pointsAreOnVertices; ++iP ) + pointsAreOnVertices = ( points[iP]->Distance( vPoints[0] ) < tol[0] || + points[iP]->Distance( vPoints[1] ) < tol[1] ); + + int nbNodes = nodeParams.size() - 2; // 2 straight edges + if ( !pointsAreOnVertices ) + nbNodes = ( nodeParams.size() - 3 ) / 2; // 1 straight edge + if ( myLayerPositions.empty() ) { - myLayerPositions.resize( nodeParams.size() - 2 ); + myLayerPositions.resize( nbNodes ); } else if ( myDistributionHypo || myNbLayerHypo ) { @@ -1048,8 +1067,10 @@ bool StdMeshers_RadialQuadrangle_1D2D::computeLayerPositions(const gp_Pnt& mesh->GetSubMesh( linEdge )->ComputeStateEngine( SMESH_subMesh::CLEAN ); if ( linEdgeComputed ) *linEdgeComputed = false; } - else if ( myLayerPositions.size() != nodeParams.size()-2 ) { - return error("Radial edge is meshed by other algorithm"); + else { + + if ( myLayerPositions.size() != nbNodes ) + return error("Radial edge is meshed by other algorithm"); } } } diff --git a/src/StdMeshers/StdMeshers_Regular_1D.cxx b/src/StdMeshers/StdMeshers_Regular_1D.cxx index 391bd38c3..951414c53 100644 --- a/src/StdMeshers/StdMeshers_Regular_1D.cxx +++ b/src/StdMeshers/StdMeshers_Regular_1D.cxx @@ -119,9 +119,8 @@ bool StdMeshers_Regular_1D::CheckHypothesis _hypType = NONE; _quadraticMesh = false; - const bool ignoreAuxiliaryHyps = false; const list & hyps = - GetUsedHypothesis(aMesh, aShape, ignoreAuxiliaryHyps); + GetUsedHypothesis(aMesh, aShape, /*ignoreAuxiliaryHyps=*/false); // find non-auxiliary hypothesis const SMESHDS_Hypothesis *theHyp = 0; @@ -377,10 +376,14 @@ static void compensateError(double a1, double an, } double q = dUn / ( nPar - 1 ); - if ( !adjustNeighbors2an ) { - for ( itU = theParams.rbegin(), i = 1; i < nPar; itU++, i++ ) { + if ( !adjustNeighbors2an ) + { + q = Abs( dUn / ( Utgt - Un )); // factor of segment length change + for ( itU = theParams.rbegin(), i = 1; i < nPar; i++ ) { + double prevU = *itU; (*itU) += dUn; - dUn -= q; + ++itU; + dUn = q * (*itU - prevU) * (prevU-U1)/(Un-U1); } } else { @@ -627,7 +630,7 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, bool computed = sm->IsMeshComputed(); if (!computed) { if (sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) { - sm->ComputeStateEngine(SMESH_subMesh::COMPUTE); + _gen->Compute( theMesh, _mainEdge, /*anUpward=*/true); computed = sm->IsMeshComputed(); } } @@ -731,6 +734,9 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, double a1 = _value[ BEG_LENGTH_IND ]; double an = _value[ END_LENGTH_IND ]; double q = ( theLength - a1 ) / ( theLength - an ); + if ( q < theLength/1e6 || 1.01*theLength < a1 + an) + return error ( SMESH_Comment("Invalid segment lengths (")< numeric_limits::min() ? ( 1+( an-a1 )/q ) : ( 1+theLength/a1 )); @@ -941,23 +950,43 @@ bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & t if (!idFirst || !idLast) return error( COMPERR_BAD_INPUT_MESH, "No node on vertex"); + // remove elements created by e.g. patern mapping (PAL21999) + // CLEAN event is incorrectly ptopagated seemingly due to Propagation hyp + // so TEMPORARY solution is to clean the submesh manually + //theMesh.GetSubMesh(theShape)->ComputeStateEngine( SMESH_subMesh::CLEAN ); + if (SMESHDS_SubMesh * subMeshDS = meshDS->MeshElements(theShape)) + { + SMDS_ElemIteratorPtr ite = subMeshDS->GetElements(); + while (ite->more()) + meshDS->RemoveFreeElement(ite->next(), subMeshDS); + SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes(); + while (itn->more()) { + const SMDS_MeshNode * node = itn->next(); + if ( node->NbInverseElements() == 0 ) + meshDS->RemoveFreeNode(node, subMeshDS); + else + meshDS->RemoveNode(node); + } + } + if (!Curve.IsNull()) { list< double > params; bool reversed = false; if ( theMesh.GetShapeToMesh().ShapeType() >= TopAbs_WIRE ) { + // if the shape to mesh is WIRE or EDGE reversed = ( EE.Orientation() == TopAbs_REVERSED ); } if ( !_mainEdge.IsNull() ) { + // take into account reversing the edge the hypothesis is propagated from reversed = ( _mainEdge.Orientation() == TopAbs_REVERSED ); + int mainID = meshDS->ShapeToIndex(_mainEdge); + if ( std::find( _revEdgesIDs.begin(), _revEdgesIDs.end(), mainID) != _revEdgesIDs.end()) + reversed = !reversed; } - else if ( _revEdgesIDs.size() > 0 ) { - for ( int i = 0; i < _revEdgesIDs.size(); i++) { - if ( _revEdgesIDs[i] == shapeID ) { - reversed = !reversed; - } - } - } + // take into account this edge reversing + if ( std::find( _revEdgesIDs.begin(), _revEdgesIDs.end(), shapeID) != _revEdgesIDs.end()) + reversed = !reversed; BRepAdaptor_Curve C3d( E ); double length = EdgeLength( E ); @@ -982,7 +1011,6 @@ bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & t parLast = f; } */ - for (list::iterator itU = params.begin(); itU != params.end(); itU++) { double param = *itU; gp_Pnt P = Curve->Value(param); @@ -1158,10 +1186,9 @@ StdMeshers_Regular_1D::GetUsedHypothesis(SMESH_Mesh & aMesh, SMESH_HypoFilter auxiliaryFilter, compatibleFilter; auxiliaryFilter.Init( SMESH_HypoFilter::IsAuxiliary() ); - const bool ignoreAux = true; - InitCompatibleHypoFilter( compatibleFilter, ignoreAux ); + InitCompatibleHypoFilter( compatibleFilter, /*ignoreAux=*/true ); - // get non-auxiliary assigned to aShape + // get non-auxiliary assigned directly to aShape int nbHyp = aMesh.GetHypotheses( aShape, compatibleFilter, _usedHypList, false ); if (nbHyp == 0 && aShape.ShapeType() == TopAbs_EDGE) diff --git a/src/StdMeshersGUI/Makefile.am b/src/StdMeshersGUI/Makefile.am index 7e76cbe67..9d9875d14 100644 --- a/src/StdMeshersGUI/Makefile.am +++ b/src/StdMeshersGUI/Makefile.am @@ -16,13 +16,12 @@ # # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # - # SMESH StdMeshersGUI : GUI for StdMeshers plugin # File : Makefile.in # Author : Julia DOROVSKIKH # Modified by : Alexander BORODIN (OCN) - autotools usage # Module : SMESH -# + include $(top_srcdir)/adm_local/unix/make_common_starter.am # header files @@ -33,12 +32,14 @@ salomeinclude_HEADERS = \ StdMeshersGUI_DistrTable.h \ StdMeshersGUI_NbSegmentsCreator.h \ StdMeshersGUI_ObjectReferenceParamWdg.h \ + StdMeshersGUI_QuadrangleParamWdg.h \ StdMeshersGUI_LayerDistributionParamWdg.h \ StdMeshersGUI_FixedPointsParamWdg.h \ StdMeshersGUI_SubShapeSelectorWdg.h # Libraries targets lib_LTLIBRARIES = libStdMeshersGUI.la + dist_libStdMeshersGUI_la_SOURCES = \ StdMeshersGUI.cxx \ StdMeshersGUI_StdHypothesisCreator.cxx \ @@ -46,6 +47,7 @@ dist_libStdMeshersGUI_la_SOURCES = \ StdMeshersGUI_DistrTable.cxx \ StdMeshersGUI_NbSegmentsCreator.cxx \ StdMeshersGUI_ObjectReferenceParamWdg.cxx \ + StdMeshersGUI_QuadrangleParamWdg.cxx \ StdMeshersGUI_LayerDistributionParamWdg.cxx \ StdMeshersGUI_FixedPointsParamWdg.cxx \ StdMeshersGUI_SubShapeSelectorWdg.cxx @@ -56,6 +58,7 @@ MOC_FILES = \ StdMeshersGUI_DistrTable_moc.cxx \ StdMeshersGUI_NbSegmentsCreator_moc.cxx \ StdMeshersGUI_ObjectReferenceParamWdg_moc.cxx \ + StdMeshersGUI_QuadrangleParamWdg_moc.cxx \ StdMeshersGUI_LayerDistributionParamWdg_moc.cxx \ StdMeshersGUI_FixedPointsParamWdg_moc.cxx \ StdMeshersGUI_SubShapeSelectorWdg_moc.cxx @@ -100,4 +103,5 @@ libStdMeshersGUI_la_LDFLAGS = \ # resources files nodist_salomeres_DATA= \ StdMeshers_images.qm \ - StdMeshers_msg_en.qm + StdMeshers_msg_en.qm \ + StdMeshers_msg_fr.qm diff --git a/src/StdMeshersGUI/StdMeshersGUI_NbSegmentsCreator.h b/src/StdMeshersGUI/StdMeshersGUI_NbSegmentsCreator.h index f50b19433..a66a82552 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_NbSegmentsCreator.h +++ b/src/StdMeshersGUI/StdMeshersGUI_NbSegmentsCreator.h @@ -92,7 +92,7 @@ private: QLabel *myLScale, *myLTable, *myLExpr, *myInfo; QGridLayout* myGroupLayout; int myTableRow, myPreviewRow; - QRadioButton* myCutNeg; + //QRadioButton* myCutNeg; QGroupBox* myReversedEdgesBox; StdMeshersGUI_SubShapeSelectorWdg* myDirectionWidget; diff --git a/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx b/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx index 06f2431ec..e69489aeb 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx @@ -35,9 +35,11 @@ #include #include #include +#include // SALOME KERNEL incldues #include +#include // Qt includes #include @@ -54,8 +56,8 @@ //================================================================================ StdMeshersGUI_ObjectReferenceParamWdg::StdMeshersGUI_ObjectReferenceParamWdg -( SUIT_SelectionFilter* f, QWidget* parent) - : QWidget( parent ) +( SUIT_SelectionFilter* f, QWidget* parent, bool multiSelection) + : QWidget( parent ), myMultiSelection( multiSelection ) { myFilter = f; init(); @@ -69,8 +71,8 @@ StdMeshersGUI_ObjectReferenceParamWdg::StdMeshersGUI_ObjectReferenceParamWdg //================================================================================ StdMeshersGUI_ObjectReferenceParamWdg::StdMeshersGUI_ObjectReferenceParamWdg -( MeshObjectType objType, QWidget* parent ) - : QWidget( parent ) +( MeshObjectType objType, QWidget* parent, bool multiSelection ) + : QWidget( parent ), myMultiSelection( multiSelection ) { myFilter = new SMESH_TypeFilter( objType ); init(); @@ -84,7 +86,10 @@ StdMeshersGUI_ObjectReferenceParamWdg::StdMeshersGUI_ObjectReferenceParamWdg StdMeshersGUI_ObjectReferenceParamWdg::~StdMeshersGUI_ObjectReferenceParamWdg() { if ( myFilter ) + { + mySelectionMgr->removeFilter( myFilter ); delete myFilter; + } } @@ -184,7 +189,7 @@ void StdMeshersGUI_ObjectReferenceParamWdg::AvoidSimultaneousSelection void StdMeshersGUI_ObjectReferenceParamWdg::SetObject(CORBA::Object_ptr obj) { - myObject = CORBA::Object::_nil(); + myObjects.clear(); myObjNameLineEdit->setText( "" ); myParamValue = ""; @@ -194,11 +199,43 @@ void StdMeshersGUI_ObjectReferenceParamWdg::SetObject(CORBA::Object_ptr obj) if ( sobj ) { std::string name = sobj->GetName(); myObjNameLineEdit->setText( name.c_str() ); - myObject = CORBA::Object::_duplicate( obj ); + myObjects.push_back( CORBA::Object::_duplicate( obj )); myParamValue = sobj->GetID().c_str(); } } +//================================================================================ +/*! + * \brief Initialize selected objects + * \param objects - entries of objects + */ +//================================================================================ + +void StdMeshersGUI_ObjectReferenceParamWdg::SetObjects(SMESH::string_array_var& objects) +{ + myObjects.clear(); + myObjNameLineEdit->setText( "" ); + myParamValue = ""; + + for ( unsigned i = 0; i < objects->length(); ++i ) + { + _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); + _PTR(SObject) aSObj = aStudy->FindObjectID(objects[i].in()); + CORBA::Object_var anObj = SMESH::SObjectToObject(aSObj,aStudy); + if ( !CORBA::is_nil( anObj )) { + std::string name = aSObj->GetName(); + QString text = myObjNameLineEdit->text(); + if ( !text.isEmpty() ) + text += " "; + text += name.c_str(); + myObjNameLineEdit->setText( text ); + myObjects.push_back( anObj ); + myParamValue += " "; + myParamValue += objects[i]; + } + } +} + //================================================================================ /*! * \brief Takes selected object @@ -212,7 +249,26 @@ void StdMeshersGUI_ObjectReferenceParamWdg::onSelectionDone() SALOME_ListIO aList; mySelectionMgr->selectedObjects(aList); if (aList.Extent() == 1) + { obj = SMESH::IObjectToObject( aList.First() ); - SetObject( obj.in() ); + SetObject( obj.in() ); + } + else if (myMultiSelection) + { + SMESH::string_array_var objIds = new SMESH::string_array; + objIds->length( aList.Extent()); + SALOME_ListIteratorOfListIO io( aList ); + int i = 0; + for ( ; io.More(); io.Next(), ++i ) + { + Handle(SALOME_InteractiveObject) anIO = io.Value(); + if ( anIO->hasEntry() ) + objIds[i] = anIO->getEntry(); + else + i--; + } + objIds->length(i); + SetObjects( objIds ); + } } } diff --git a/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.h b/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.h index c5fabc25e..e8c387194 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.h +++ b/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.h @@ -37,6 +37,8 @@ // CORBA includes #include +#include CORBA_SERVER_HEADER(SMESH_Mesh) + class SUIT_SelectionFilter; class SMESHGUI; class LightApp_SelectionMgr; @@ -52,22 +54,29 @@ class STDMESHERSGUI_EXPORT StdMeshersGUI_ObjectReferenceParamWdg : public QWidge public: StdMeshersGUI_ObjectReferenceParamWdg( SUIT_SelectionFilter* filter, - QWidget* parent); + QWidget* parent, + bool multiSelection=false); StdMeshersGUI_ObjectReferenceParamWdg( MeshObjectType objType, - QWidget* parent); + QWidget* parent, + bool multiSelection=false); ~StdMeshersGUI_ObjectReferenceParamWdg(); void SetObject(CORBA::Object_ptr obj); + void SetObjects(SMESH::string_array_var& objEntries); + template - typename TInterface::_var_type GetObject() const { - if ( IsObjectSelected() ) return TInterface::_narrow(myObject); + typename TInterface::_var_type GetObject(unsigned i=0) const { + if ( IsObjectSelected(i) ) return TInterface::_narrow(myObjects[i]); return TInterface::_nil(); } + int NbObjects() const { return myObjects.size(); } + QString GetValue() const { return myParamValue; } - bool IsObjectSelected() const { return !CORBA::is_nil(myObject); } + bool IsObjectSelected(unsigned i=0) const + { return i < myObjects.size() && !CORBA::is_nil(myObjects[i]); } void AvoidSimultaneousSelection( StdMeshersGUI_ObjectReferenceParamWdg* other); @@ -97,7 +106,10 @@ private: void init(); private: - CORBA::Object_var myObject; + + bool myMultiSelection; + std::vector myObjects; + SUIT_SelectionFilter* myFilter; bool mySelectionActivated; diff --git a/src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.cxx b/src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.cxx new file mode 100644 index 000000000..ccb38c670 --- /dev/null +++ b/src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.cxx @@ -0,0 +1,100 @@ +// Copyright (C) 2007-2010 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 : StdMeshersGUI_QuadrangleParamWdg.cxx +// Author : Open CASCADE S.A.S. (jfa) +// SMESH includes + +#include "StdMeshersGUI_QuadrangleParamWdg.h" + +#include "SMESHGUI.h" + +#include "SUIT_ResourceMgr.h" + +// Qt includes +#include +#include +#include +#include + +// IDL includes +#include +#include CORBA_CLIENT_HEADER(SMESH_BasicHypothesis) + +#define SPACING 6 +#define MARGIN 0 + +//================================================================================ +// function : Constructor +// purpose : +//================================================================================ +StdMeshersGUI_QuadrangleParamWdg::StdMeshersGUI_QuadrangleParamWdg (QWidget * parent) + : QWidget(parent), + myType(0) +{ + myType = new QButtonGroup (this); + + QGridLayout* typeLay = new QGridLayout( this ); + + typeLay->setMargin(MARGIN); + typeLay->setSpacing(SPACING); + + QString aTypeKey ("SMESH_QUAD_TYPE_%1"); + QString aPictKey ("ICON_StdMeshers_Quadrangle_Params_%1"); + + int itype = 0; + for (; itype < int(StdMeshers::QUAD_NB_TYPES); itype++) { + QRadioButton* rbi = new QRadioButton (tr(aTypeKey.arg(itype).toLatin1()), this); + QPixmap pmi (SMESHGUI::resourceMgr()->loadPixmap("SMESH", tr(aPictKey.arg(itype).toLatin1()))); + QLabel* pli = new QLabel (this); + pli->setPixmap(pmi); + typeLay->addWidget(rbi, itype, 0, 1, 1); + typeLay->addWidget(pli, itype, 1, 1, 1); + myType->addButton(rbi, itype); + } + myType->button(0)->setChecked(true); + + setLayout(typeLay); + setMinimumWidth(300); +} + +//================================================================================ +// function : Destructor +// purpose : +//================================================================================ +StdMeshersGUI_QuadrangleParamWdg::~StdMeshersGUI_QuadrangleParamWdg() +{ +} + +//================================================================================= +// function : SetType +// purpose : +//================================================================================= +void StdMeshersGUI_QuadrangleParamWdg::SetType (int theType) +{ + myType->button(theType)->setChecked(true); +} + +//================================================================================= +// function : GetType +// purpose : +//================================================================================= +int StdMeshersGUI_QuadrangleParamWdg::GetType() +{ + return myType->checkedId(); +} diff --git a/src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.h b/src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.h new file mode 100644 index 000000000..2d5abdc45 --- /dev/null +++ b/src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.h @@ -0,0 +1,49 @@ +// Copyright (C) 2007-2010 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 : StdMeshersGUI_QuadrangleParamWdg.h +// Author : Open CASCADE S.A.S. (jfa) + +#ifndef STDMESHERSGUI_QUADRANGLEPARAMWDG_H +#define STDMESHERSGUI_QUADRANGLEPARAMWDG_H + +// SMESH includes +#include "SMESH_StdMeshersGUI.hxx" + +// Qt includes +#include + +class QButtonGroup; + +class STDMESHERSGUI_EXPORT StdMeshersGUI_QuadrangleParamWdg : public QWidget +{ + Q_OBJECT + +public: + StdMeshersGUI_QuadrangleParamWdg (QWidget* parent = 0); + ~StdMeshersGUI_QuadrangleParamWdg(); + + void SetType (int theType); + int GetType (); + +private: + // Quadranle preference, Triangle preference, Reduced + QButtonGroup* myType; +}; + +#endif // STDMESHERSGUI_QUADRANGLEPARAMWDG_H diff --git a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx index 8fd24f351..9595e67a0 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx @@ -19,23 +19,26 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // +// File : StdMeshersGUI_StdHypothesisCreator.cxx +// Author : Alexander SOLOVYOV, Open CASCADE S.A.S. +// SMESH includes -// File : StdMeshersGUI_StdHypothesisCreator.cxx -// Author : Alexander SOLOVYOV, Open CASCADE S.A.S. -// SMESH includes -// #include "StdMeshersGUI_StdHypothesisCreator.h" #include #include #include #include + #include #include -#include "StdMeshersGUI_ObjectReferenceParamWdg.h" + +#include "StdMeshersGUI_FixedPointsParamWdg.h" #include "StdMeshersGUI_LayerDistributionParamWdg.h" +#include "StdMeshersGUI_ObjectReferenceParamWdg.h" +#include "StdMeshersGUI_QuadrangleParamWdg.h" #include "StdMeshersGUI_SubShapeSelectorWdg.h" -#include "StdMeshersGUI_FixedPointsParamWdg.h" + #include // SALOME GUI includes @@ -45,6 +48,7 @@ #include #include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) #include CORBA_SERVER_HEADER(SMESH_Mesh) +#include CORBA_SERVER_HEADER(SMESH_Group) // Qt includes #include @@ -187,10 +191,10 @@ namespace { */ //================================================================================ - class TDoubleSliderWith2Lables: public QWidget + class TDoubleSliderWith2Labels: public QWidget { public: - TDoubleSliderWith2Lables( const QString& leftLabel, const QString& rightLabel, + TDoubleSliderWith2Labels( const QString& leftLabel, const QString& rightLabel, const double initValue, const double bottom, const double top , const double precision, QWidget * parent=0 , const char * name=0 ) @@ -199,7 +203,7 @@ namespace { setObjectName(name); QHBoxLayout* aHBoxL = new QHBoxLayout(this); - + if ( !leftLabel.isEmpty() ) { QLabel* aLeftLabel = new QLabel( this ); aLeftLabel->setText( leftLabel ); @@ -258,6 +262,25 @@ namespace { return SMESH::SMESH_Mesh::_nil(); } //================================================================================ + /*! + * \brief Retrieve SMESH_Mesh held by widget + */ + //================================================================================ + + inline SMESH::ListOfGroups_var groupsFromWdg(const QWidget* wdg) + { + SMESH::ListOfGroups_var groups = new SMESH::ListOfGroups; + const StdMeshersGUI_ObjectReferenceParamWdg * objRefWdg = + dynamic_cast( wdg ); + if ( objRefWdg ) + { + groups->length( objRefWdg->NbObjects() ); + for ( unsigned i = 0; i < groups->length(); ++i ) + groups[i] = objRefWdg->GetObject< SMESH::SMESH_GroupBase >(i); + } + return groups; + } + //================================================================================ /*! * \brief creates a filter for selection of shapes of given dimension * \param dim - dimension @@ -314,6 +337,15 @@ namespace { w->SetObject( object.in() ); return w; } + QWidget* newObjRefParamWdg( SUIT_SelectionFilter* filter, + SMESH::string_array_var& objEntries) + { + StdMeshersGUI_ObjectReferenceParamWdg* w = + new StdMeshersGUI_ObjectReferenceParamWdg( filter, 0, /*multiSel=*/true); + w->SetObjects( objEntries ); + w->activateSelection(); + return w; + } //================================================================================ /*! @@ -379,6 +411,12 @@ bool StdMeshersGUI_StdHypothesisCreator::checkParams( QString& msg ) const if ( ok ) deactivateObjRefParamWdg( customWidgets() ); } + else if ( hypType().startsWith("ImportSource" )) + { + StdMeshersGUI_ObjectReferenceParamWdg* w = + widget< StdMeshersGUI_ObjectReferenceParamWdg >( 0 ); + ok = ( w->IsObjectSelected() ); + } else if ( hypType() == "LayerDistribution" || hypType() == "LayerDistribution2D" ) { StdMeshersGUI_LayerDistributionParamWdg* w = @@ -387,9 +425,11 @@ bool StdMeshersGUI_StdHypothesisCreator::checkParams( QString& msg ) const } else if ( hypType() == "QuadrangleParams" ) { - StdMeshersGUI_SubShapeSelectorWdg* w = - widget< StdMeshersGUI_SubShapeSelectorWdg >( 0 ); - ok = ( w->GetListSize() > 0 ); + //StdMeshersGUI_SubShapeSelectorWdg* w = + // widget< StdMeshersGUI_SubShapeSelectorWdg >( 0 ); + //ok = ( w->GetListSize() > 0 ); + //StdMeshersGUI_QuadrangleParamWdg* w = + // widget< StdMeshersGUI_QuadrangleParamWdg >( 1 ); } return ok; } @@ -604,18 +644,43 @@ QString StdMeshersGUI_StdHypothesisCreator::storeParams() const geomFromWdg ( getWidgetForParam( 3 )), // tgt1 geomFromWdg ( getWidgetForParam( 5 ))); // tgt2 } + else if( hypType()=="ImportSource1D" ) + { + StdMeshers::StdMeshers_ImportSource1D_var h = + StdMeshers::StdMeshers_ImportSource1D::_narrow( hypothesis() ); + + SMESH::ListOfGroups_var groups = groupsFromWdg( getWidgetForParam( 0 )); + h->SetSourceEdges( groups.in() ); + QCheckBox* toCopyMesh = widget< QCheckBox >( 1 ); + QCheckBox* toCopyGroups = widget< QCheckBox >( 2 ); + h->SetCopySourceMesh( toCopyMesh->isChecked(), toCopyGroups->isChecked()); + } + else if( hypType()=="ImportSource2D" ) + { + StdMeshers::StdMeshers_ImportSource2D_var h = + StdMeshers::StdMeshers_ImportSource2D::_narrow( hypothesis() ); + + SMESH::ListOfGroups_var groups = groupsFromWdg( getWidgetForParam( 0 )); + h->SetSourceFaces( groups.in() ); + QCheckBox* toCopyMesh = widget< QCheckBox >( 1 ); + QCheckBox* toCopyGroups = widget< QCheckBox >( 2 ); + h->SetCopySourceMesh( toCopyMesh->isChecked(), toCopyGroups->isChecked()); + } else if( hypType()=="QuadrangleParams" ) { StdMeshers::StdMeshers_QuadrangleParams_var h = StdMeshers::StdMeshers_QuadrangleParams::_narrow( hypothesis() ); - StdMeshersGUI_SubShapeSelectorWdg* w = + StdMeshersGUI_SubShapeSelectorWdg* w1 = widget< StdMeshersGUI_SubShapeSelectorWdg >( 0 ); - if (w) { - if( w->GetListSize() > 0 ) { - h->SetTriaVertex( w->GetListOfIDs()[0] ); // getlist must be called once - const char * entry = w->GetMainShapeEntry(); - h->SetObjectEntry( entry ); + StdMeshersGUI_QuadrangleParamWdg* w2 = + widget< StdMeshersGUI_QuadrangleParamWdg >( 1 ); + if (w1 && w2) { + if (w1->GetListSize() > 0) { + h->SetTriaVertex(w1->GetListOfIDs()[0]); // getlist must be called once + const char * entry = w1->GetMainShapeEntry(); + h->SetObjectEntry(entry); } + h->SetQuadType(StdMeshers::QuadType(w2->GetType())); } } } @@ -860,8 +925,10 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const item.myName = tr( "SMESH_FINENESS_PARAM" ); //item.myValue = h->GetFineness(); p.append( item ); - customWidgets()->append - ( new TDoubleSliderWith2Lables( "0 ", " 1", h->GetFineness(), 0, 1, 0.01, 0 )); + SMESHGUI_SpinBox* _autoLengthSpinBox = new SMESHGUI_SpinBox(dlg()); + _autoLengthSpinBox->RangeStepAndValidator(0, 1, 0.01, "length_precision"); + _autoLengthSpinBox->SetValue(h->GetFineness()); + customWidgets()->append( _autoLengthSpinBox); } else if( hypType()=="NumberOfLayers" ) { @@ -982,13 +1049,63 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const customWidgets()->append( newObjRefParamWdg( filterForShapeOfDim( 0 ), h->GetTargetVertex( 2 ))); } - else if( hypType()=="QuadrangleParams" ) + else if( hypType()=="ImportSource1D" ) + { + StdMeshers::StdMeshers_ImportSource1D_var h = + StdMeshers::StdMeshers_ImportSource1D::_narrow( hyp ); + + SMESH::string_array_var groupEntries = h->GetSourceEdges(); + CORBA::Boolean toCopyMesh, toCopyGroups; + h->GetCopySourceMesh(toCopyMesh, toCopyGroups); + + item.myName = tr( "SMESH_SOURCE_EDGES" ); p.append( item ); + customWidgets()->append( newObjRefParamWdg( new SMESH_TypeFilter( GROUP_EDGE ), + groupEntries)); + + item.myName = tr( "SMESH_COPY_MESH" ); p.append( item ); + QCheckBox* aQCheckBox = new QCheckBox(dlg()); + aQCheckBox->setChecked( toCopyMesh ); + connect( aQCheckBox, SIGNAL( stateChanged(int) ), this, SLOT( onValueChanged() )); + customWidgets()->append( aQCheckBox ); + + item.myName = tr( "SMESH_TO_COPY_GROUPS" ); p.append( item ); + aQCheckBox = new QCheckBox(dlg()); + aQCheckBox->setChecked( toCopyGroups ); + aQCheckBox->setEnabled( toCopyMesh ); + customWidgets()->append( aQCheckBox ); + } + else if( hypType()=="ImportSource2D" ) + { + StdMeshers::StdMeshers_ImportSource2D_var h = + StdMeshers::StdMeshers_ImportSource2D::_narrow( hyp ); + + SMESH::string_array_var groupEntries = h->GetSourceFaces(); + CORBA::Boolean toCopyMesh, toCopyGroups; + h->GetCopySourceMesh(toCopyMesh, toCopyGroups); + + item.myName = tr( "SMESH_SOURCE_FACES" ); p.append( item ); + customWidgets()->append( newObjRefParamWdg( new SMESH_TypeFilter( GROUP_FACE ), + groupEntries)); + + item.myName = tr( "SMESH_COPY_MESH" ); p.append( item ); + QCheckBox* aQCheckBox = new QCheckBox(dlg()); + aQCheckBox->setChecked( toCopyMesh ); + connect( aQCheckBox, SIGNAL( stateChanged(int) ), this, SLOT( onValueChanged() )); + customWidgets()->append( aQCheckBox ); + + item.myName = tr( "SMESH_COPY_GROUPS" ); p.append( item ); + aQCheckBox = new QCheckBox(dlg()); + aQCheckBox->setChecked( toCopyGroups ); + aQCheckBox->setEnabled( toCopyMesh ); + customWidgets()->append( aQCheckBox ); + } + else if (hypType() == "QuadrangleParams") { StdMeshers::StdMeshers_QuadrangleParams_var h = - StdMeshers::StdMeshers_QuadrangleParams::_narrow( hyp ); + StdMeshers::StdMeshers_QuadrangleParams::_narrow(hyp); - item.myName = tr( "SMESH_BASE_VERTEX" ); - p.append( item ); + item.myName = tr("SMESH_BASE_VERTEX"); + p.append(item); StdMeshersGUI_SubShapeSelectorWdg* aDirectionWidget = new StdMeshersGUI_SubShapeSelectorWdg(); @@ -996,21 +1113,32 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const aDirectionWidget->SetSubShType(TopAbs_VERTEX); QString anEntry = SMESHGUI_GenericHypothesisCreator::getShapeEntry(); QString aMainEntry = SMESHGUI_GenericHypothesisCreator::getMainShapeEntry(); - if ( anEntry == "" ) + if (anEntry == "") anEntry = h->GetObjectEntry(); - aDirectionWidget->SetGeomShapeEntry( anEntry ); - aDirectionWidget->SetMainShapeEntry( aMainEntry ); - if ( !isCreation() ) { + aDirectionWidget->SetGeomShapeEntry(anEntry); + aDirectionWidget->SetMainShapeEntry(aMainEntry); + if (!isCreation()) { SMESH::long_array_var aVec = new SMESH::long_array; int vertID = h->GetTriaVertex(); - if(vertID>0) { + if (vertID > 0) { aVec->length(1); aVec[0] = vertID; - aDirectionWidget->SetListOfIDs( aVec ); + aDirectionWidget->SetListOfIDs(aVec); } } - aDirectionWidget->showPreview( true ); - customWidgets()->append ( aDirectionWidget ); + aDirectionWidget->showPreview(true); + + item.myName = tr("SMESH_QUAD_TYPE"); + p.append(item); + + StdMeshersGUI_QuadrangleParamWdg* aTypeWidget = + new StdMeshersGUI_QuadrangleParamWdg(); + if (!isCreation()) { + aTypeWidget->SetType(int(h->GetQuadType())); + } + + customWidgets()->append(aDirectionWidget); + customWidgets()->append(aTypeWidget); } else res = false; @@ -1129,6 +1257,8 @@ QString StdMeshersGUI_StdHypothesisCreator::hypTypeName( const QString& t ) cons types.insert( "ProjectionSource1D", "PROJECTION_SOURCE_1D" ); types.insert( "ProjectionSource2D", "PROJECTION_SOURCE_2D" ); types.insert( "ProjectionSource3D", "PROJECTION_SOURCE_3D" ); + types.insert( "ImportSource1D", "IMPORT_SOURCE_1D" ); + types.insert( "ImportSource2D", "IMPORT_SOURCE_2D" ); types.insert( "NumberOfLayers", "NUMBER_OF_LAYERS" ); types.insert( "LayerDistribution", "LAYER_DISTRIBUTION" ); types.insert( "NumberOfLayers2D", "NUMBER_OF_LAYERS_2D" ); @@ -1181,9 +1311,9 @@ bool StdMeshersGUI_StdHypothesisCreator::getParamFromCustomWidget( StdParam & pa QWidget* widget) const { if ( hypType()=="AutomaticLength" ) { - TDoubleSliderWith2Lables* w = dynamic_cast( widget ); + SMESHGUI_SpinBox* w = dynamic_cast( widget ); if ( w ) { - param.myValue = w->value(); + param.myValue = w->GetValue(); return true; } } @@ -1215,6 +1345,13 @@ bool StdMeshersGUI_StdHypothesisCreator::getParamFromCustomWidget( StdParam & pa param.myValue = w->GetValue(); return true; } + if ( widget->inherits( "StdMeshersGUI_QuadrangleParamWdg" )) + { + //const StdMeshersGUI_QuadrangleParamWdg * w = + // static_cast( widget ); + param.myValue = "QuadType"; + return true; + } if ( widget->inherits( "StdMeshersGUI_FixedPointsParamWdg" )) { const StdMeshersGUI_FixedPointsParamWdg * w = @@ -1222,6 +1359,12 @@ bool StdMeshersGUI_StdHypothesisCreator::getParamFromCustomWidget( StdParam & pa param.myValue = w->GetValue(); return true; } + if ( widget->inherits( "QCheckBox" )) + { + //const QCheckBox * w = static_cast( widget ); + //param.myValue = w->isChecked(); + return true; + } return false; } @@ -1233,7 +1376,8 @@ bool StdMeshersGUI_StdHypothesisCreator::getParamFromCustomWidget( StdParam & pa void StdMeshersGUI_StdHypothesisCreator::onReject() { - if ( hypType().startsWith("ProjectionSource" )) + if ( hypType().startsWith("ProjectionSource" ) || + hypType().startsWith("ImportSource" )) { // Uninstall filters of StdMeshersGUI_ObjectReferenceParamWdg deactivateObjRefParamWdg( customWidgets() ); @@ -1242,13 +1386,14 @@ void StdMeshersGUI_StdHypothesisCreator::onReject() //================================================================================ /*! - * \brief + * \brief Update widgets dependent on paramWidget */ //================================================================================ void StdMeshersGUI_StdHypothesisCreator::valueChanged( QWidget* paramWidget) { - if ( hypType() == "MaxLength" && paramWidget == getWidgetForParam(1) ) { + if ( hypType() == "MaxLength" && paramWidget == getWidgetForParam(1) ) + { getWidgetForParam(0)->setEnabled( !widget< QCheckBox >( 1 )->isChecked() ); if ( !getWidgetForParam(0)->isEnabled() ) { StdMeshers::StdMeshers_MaxLength_var h = @@ -1256,6 +1401,20 @@ void StdMeshersGUI_StdHypothesisCreator::valueChanged( QWidget* paramWidget) widget< QtxDoubleSpinBox >( 0 )->setValue( h->GetPreestimatedLength() ); } } + else if ( hypType().startsWith("ImportSource") && paramWidget == getWidgetForParam(1) ) + { + QCheckBox* toCopyMesh = (QCheckBox*) paramWidget; + QCheckBox* toCopyGroups = widget< QCheckBox >( 2 ); + if ( !toCopyMesh->isChecked() ) + { + toCopyGroups->setChecked( false ); + toCopyGroups->setEnabled( false ); + } + else + { + toCopyGroups->setEnabled( true ); + } + } } //================================================================================ diff --git a/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx b/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx index 4bc2b7549..9a8e3827c 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx @@ -24,14 +24,15 @@ #include "StdMeshersGUI_SubShapeSelectorWdg.h" // SMESH Includes -#include +#include "SMESH_Type.h" #include "SMESHGUI_MeshUtils.h" -#include -#include -#include +#include "SMESH_Actor.h" +#include "SMESH_PreviewActorsCollection.h" +#include "SMESH_ActorUtils.h" #include "SMESHGUI_GroupUtils.h" #include "SMESH_Gen_i.hxx" #include "SMESHGUI_GEOMGenUtils.h" +#include "SMESH_LogicalFilter.hxx" // SVTK Includes #include @@ -49,6 +50,8 @@ // GEOM Includes #include +#include +#include // Qt includes #include @@ -63,10 +66,12 @@ #include #include #include +#include // SALOME KERNEL includes #include + #define SPACING 6 #define MARGIN 0 @@ -128,6 +133,14 @@ StdMeshersGUI_SubShapeSelectorWdg::~StdMeshersGUI_SubShapeSelectorWdg() myEntry = ""; myParamValue = ""; myMainShape.Nullify(); + + if ( mySelectionMgr && myFilter ) + mySelectionMgr->removeFilter( myFilter ); + delete myFilter; myFilter=0; + + SUIT_SelectionFilter* filter; + foreach( filter, myGeomFilters ) + delete filter; } //================================================================================ @@ -153,6 +166,16 @@ void StdMeshersGUI_SubShapeSelectorWdg::init() if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode( ActorSelection ); + + SalomeApp_Study* study = mySMESHGUI->activeStudy(); + GEOM_EdgeFilter* edgeFilter = new GEOM_EdgeFilter(study,StdSelect_AnyEdge); + GEOM_CompoundFilter* gpoupFilter = new GEOM_CompoundFilter(study); + gpoupFilter->addSubType( TopAbs_EDGE ); + myGeomFilters.append( edgeFilter ); + myGeomFilters.append( gpoupFilter ); + myFilter = new SMESH_LogicalFilter( myGeomFilters, SMESH_LogicalFilter::LO_OR ); + mySelectionMgr->installFilter( myFilter ); + connect( myAddButton, SIGNAL(clicked()), SLOT(onAdd())); connect( myRemoveButton, SIGNAL(clicked()), SLOT(onRemove())); @@ -222,7 +245,8 @@ void StdMeshersGUI_SubShapeSelectorWdg::SelectionIntoArgument() aFatherEntry = aGeomFatherObj->GetStudyEntry(); } - if ( aFatherEntry != "" && ( aFatherEntry == myEntry || aFatherEntry == aMainFatherEntry ) ) { + if ( aFatherEntry != "" && ( aFatherEntry == myEntry || aFatherEntry == aMainFatherEntry ) ) + { if ( aGeomObj->GetType() == 37 /*GEOM_GROUP*/ ) { // Selected Group that belongs the main object GEOMBase::GetShape(aGeomObj, shape); if ( !shape.IsNull() ) { @@ -258,7 +282,7 @@ void StdMeshersGUI_SubShapeSelectorWdg::SelectionIntoArgument() } } // update add button - myAddButton->setEnabled( myListWidget->count() < myMaxSize && mySelectedIDs.size() > 0 && ( mySelectedIDs.size() <= myMaxSize || myMaxSize == -1 ) ); + myAddButton->setEnabled( ( myListWidget->count() < myMaxSize || myMaxSize == -1 ) && mySelectedIDs.size() > 0 && ( mySelectedIDs.size() <= myMaxSize || myMaxSize == -1 ) ); //Connect Selected Ids in viewer and dialog's Ids list myListWidget->clearSelection(); diff --git a/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.h b/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.h index b29840bdf..591d28b6f 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.h +++ b/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.h @@ -45,6 +45,7 @@ class QListWidget; class SMESH_Actor; class SMESH_PreviewActorsCollection; class vtkRenderer; +class SUIT_SelectionFilter; class STDMESHERSGUI_EXPORT StdMeshersGUI_SubShapeSelectorWdg : public QWidget { @@ -119,6 +120,8 @@ private: TopAbs_ShapeEnum mySubShType; SMESH_PreviewActorsCollection* myPreviewActor; + QList myGeomFilters; + SUIT_SelectionFilter* myFilter; }; #endif // STDMESHERSGUI_SUBSHAPESELECTORWDG_H diff --git a/src/StdMeshersGUI/StdMeshers_images.ts b/src/StdMeshersGUI/StdMeshers_images.ts index da9130846..87444b56a 100644 --- a/src/StdMeshersGUI/StdMeshers_images.ts +++ b/src/StdMeshersGUI/StdMeshers_images.ts @@ -89,6 +89,18 @@ ICON_DLG_PROJECTION_SOURCE_3D mesh_hypo_source_3d.png + + ICON_DLG_QUADRANGLE_PARAMS + mesh_hypo_length.png + + + ICON_DLG_IMPORT_SOURCE_1D + mesh_hypo_source_edge.png + + + ICON_DLG_IMPORT_SOURCE_2D + mesh_hypo_source_face.png + ICON_DLG_SEGMENT_LENGTH_AROUND_VERTEX mesh_hypo_length.png @@ -241,9 +253,28 @@ ICON_SMESH_TREE_HYPO_StartEndLength mesh_tree_hypo_length.png + + + StdMeshersGUI_QuadrangleParamWdg + + ICON_StdMeshers_Quadrangle_Params_0 + mesh_quadrangle_standard.png + - ICON_DLG_QUADRANGLE_PARAMS - mesh_hypo_length.png + ICON_StdMeshers_Quadrangle_Params_1 + mesh_quadrangle_triapref.png + + + ICON_StdMeshers_Quadrangle_Params_2 + mesh_quadrangle_quadpref.png + + + ICON_StdMeshers_Quadrangle_Params_3 + mesh_quadrangle_quadpref_reversed.png + + + ICON_StdMeshers_Quadrangle_Params_4 + mesh_quadrangle_reduced.png diff --git a/src/StdMeshersGUI/StdMeshers_msg_en.ts b/src/StdMeshersGUI/StdMeshers_msg_en.ts index 574646e01..75888dfa3 100644 --- a/src/StdMeshersGUI/StdMeshers_msg_en.ts +++ b/src/StdMeshersGUI/StdMeshers_msg_en.ts @@ -1,380 +1,417 @@ + - - - - @default - - SMESH_ARITHMETIC_1D_HYPOTHESIS - Arithmetic 1D - - - SMESH_ARITHMETIC_1D_PARAM - Arithmetic Reason - - - SMESH_ARITHMETIC_1D_TITLE - Hypothesis Construction - - - SMESH_AUTOMATIC_LENGTH_HYPOTHESIS - Automatic Length - - - SMESH_AUTOMATIC_LENGTH_TITLE - Hypothesis Construction - - - SMESH_CONV_MODE - Conversion mode - - - SMESH_CUT_NEG_MODE - Cut negative - - - SMESH_DEFLECTION1D_HYPOTHESIS - Deflection 1D - - - SMESH_DEFLECTION1D_PARAM - Deflection - - - SMESH_DEFLECTION1D_TITLE - Hypothesis Construction - - - SMESH_DENSITY_FUNC - Density function - - - SMESH_DISTR - Distribution - - - SMESH_DISTR_EXPR - Distribution with analitic density - - - SMESH_DISTR_REGULAR - Equidistant distribution - - - SMESH_DISTR_SCALE - Scale distribution - - - SMESH_DISTR_TAB - Distribution with table density - - - SMESH_DISTR_TYPE - Type of distribution - - - SMESH_END_LENGTH_PARAM - End Length - - - SMESH_EXPR_FUNC - Density function f(t) = - - - SMESH_EXP_MODE - Exponent - - - SMESH_FINENESS_PARAM - Fineness - - - SMESH_FUNC_DOMAIN - Warning: function must be defined on segment [0..1] - - - SMESH_INSERT_ROW - Insert row - - - SMESH_INVALID_FUNCTION - Function is invalid - - - SMESH_LAYERS_DISTRIBUTION - 1D Hypothesis - - - SMESH_LAYER_DISTRIBUTION_HYPOTHESIS - Distribution of Layers - - - SMESH_LAYER_DISTRIBUTION_TITLE - Hypothesis Construction - - - SMESH_LOCAL_LENGTH_HYPOTHESIS - Average Length - - - SMESH_LOCAL_LENGTH_PARAM - Length - - - SMESH_LOCAL_LENGTH_PRECISION - Precision - - - SMESH_LOCAL_LENGTH_TITLE - Hypothesis Construction - - - SMESH_FIXED_POINTS_1D_HYPOTHESIS - Fixed points 1D - - - SMESH_FIXED_POINTS_1D_TITLE - Hypothesis Construction - - - SMESH_MAX_LENGTH_HYPOTHESIS - Max Length - - - SMESH_USE_PREESTIMATED_LENGTH - Use preestimated length - - - SMESH_MAX_LENGTH_TITLE - Hypothesis Construction - - - SMESH_MAX_ELEMENT_AREA_HYPOTHESIS - Max. Element Area - - - SMESH_MAX_ELEMENT_AREA_PARAM - Max. Area - - - SMESH_MAX_ELEMENT_AREA_TITLE - Hypothesis Construction - - - SMESH_MAX_ELEMENT_VOLUME_HYPOTHESIS - Max. Element Volume - - - SMESH_MAX_ELEMENT_VOLUME_PARAM - Max. Volume - - - SMESH_MAX_ELEMENT_VOLUME_TITLE - Hypothesis Construction - - - SMESH_NB_SEGMENTS_HYPOTHESIS - Number of Segments - - - SMESH_NB_SEGMENTS_PARAM - Number of Segments - - - SMESH_NB_SEGMENTS_SCALE_PARAM - Scale Factor - - - SMESH_NB_SEGMENTS_TITLE - Hypothesis Construction - - - SMESH_NO_CONV - No conversion - - - SMESH_NUMBER_OF_LAYERS - Number of Layers - - - SMESH_NUMBER_OF_LAYERS_HYPOTHESIS - Radial Prism Parameter - - - SMESH_NUMBER_OF_LAYERS_2D_HYPOTHESIS - Radial Quadrangle Parameter - - - SMESH_NUMBER_OF_LAYERS_TITLE - Hypothesis Construction - - - SMESH_NUMBER_OF_LAYERS_2D_TITLE - Hypothesis Construction - - - SMESH_PROJECTION_SOURCE_1D_HYPOTHESIS - Projection Source 1D - - - SMESH_PROJECTION_SOURCE_1D_TITLE - Hypothesis Construction - - - SMESH_PROJECTION_SOURCE_2D_HYPOTHESIS - Projection Source 2D - - - SMESH_PROJECTION_SOURCE_2D_TITLE - Hypothesis Construction - - - SMESH_PROJECTION_SOURCE_3D_HYPOTHESIS - Projection Source 3D - - - SMESH_PROJECTION_SOURCE_3D_TITLE - Hypothesis Construction - - - SMESH_REMOVE_ROW - Remove row - - - SMESH_REVERSED_EDGES - Reversed Edges - - - SMESH_FIXED_POINTS - Fixed Points - - - SMESH_RANGE - Range - - - SMESH_NB_SEGMENTS - Nb. Segments - - - SMESH_SAME_NB_SEGMENTS - Same Nb. Segments for All Intervals - - - SMESH_BASE_VERTEX - Base vertex - - - SMESH_SEGMENT_LENGTH_AROUND_VERTEX_HYPOTHESIS - Segment Length Around Vertex - - - SMESH_SEGMENT_LENGTH_AROUND_VERTEX_PARAM - Length - - - SMESH_SEGMENT_LENGTH_AROUND_VERTEX_TITLE - Hypothesis Construction - - - SMESH_SOURCE_3DSHAPE - 3D shape - - - SMESH_SOURCE_EDGE - Edge - - - SMESH_SOURCE_FACE - Face - - - SMESH_SOURCE_MESH - Mesh - - - SMESH_SOURCE_VERTEX - Source Vertex - - - SMESH_SOURCE_VERTEX1 - Source Vertex 1 - - - SMESH_SOURCE_VERTEX2 - Source Vertex 2 - - - SMESH_START_END_LENGTH_HYPOTHESIS - Start and End local Length - - - SMESH_START_END_LENGTH_TITLE - Hypothesis Construction - - - SMESH_START_LENGTH_PARAM - Start Length - - - SMESH_TAB_FUNC - Table function - - - SMESH_TARGET_VERTEX - Target Vertex - - - SMESH_TARGET_VERTEX1 - Target Vertex 1 - - - SMESH_TARGET_VERTEX2 - Target Vertex 2 - - - SMESH_QUADRANGLE_PARAMS_HYPOTHESIS - Quadrangle parameters - - - SMESH_QUADRANGLE_PARAMS_TITLE - Hypothesis Construction - - - - StdMeshersGUI_LayerDistributionParamWdg - - CHANGE_TYPE - Change Type - - - CREATE - Create - - - EDIT - Edit - - + + + @default + + SMESH_ARITHMETIC_1D_HYPOTHESIS + Arithmetic 1D + + + SMESH_ARITHMETIC_1D_PARAM + Arithmetic Reason + + + SMESH_ARITHMETIC_1D_TITLE + Hypothesis Construction + + + SMESH_AUTOMATIC_LENGTH_HYPOTHESIS + Automatic Length + + + SMESH_AUTOMATIC_LENGTH_TITLE + Hypothesis Construction + + + SMESH_CONV_MODE + Conversion mode + + + SMESH_CUT_NEG_MODE + Cut negative + + + SMESH_DEFLECTION1D_HYPOTHESIS + Deflection 1D + + + SMESH_DEFLECTION1D_PARAM + Deflection + + + SMESH_DEFLECTION1D_TITLE + Hypothesis Construction + + + SMESH_DENSITY_FUNC + Density function + + + SMESH_DISTR + Distribution + + + SMESH_DISTR_EXPR + Distribution with analitic density + + + SMESH_DISTR_REGULAR + Equidistant distribution + + + SMESH_DISTR_SCALE + Scale distribution + + + SMESH_DISTR_TAB + Distribution with table density + + + SMESH_DISTR_TYPE + Type of distribution + + + SMESH_END_LENGTH_PARAM + End Length + + + SMESH_EXPR_FUNC + Density function f(t) = + + + SMESH_EXP_MODE + Exponent + + + SMESH_FINENESS_PARAM + Fineness + + + SMESH_FUNC_DOMAIN + Warning: function must be defined on segment [0..1] + + + SMESH_INSERT_ROW + Insert row + + + SMESH_INVALID_FUNCTION + Function is invalid + + + SMESH_LAYERS_DISTRIBUTION + 1D Hypothesis + + + SMESH_LAYER_DISTRIBUTION_HYPOTHESIS + Distribution of Layers + + + SMESH_LAYER_DISTRIBUTION_TITLE + Hypothesis Construction + + + SMESH_LOCAL_LENGTH_HYPOTHESIS + Local Length + + + SMESH_LOCAL_LENGTH_PARAM + Length + + + SMESH_LOCAL_LENGTH_PRECISION + Precision + + + SMESH_LOCAL_LENGTH_TITLE + Hypothesis Construction + + + SMESH_FIXED_POINTS_1D_HYPOTHESIS + Fixed points 1D + + + SMESH_FIXED_POINTS_1D_TITLE + Hypothesis Construction + + + SMESH_MAX_LENGTH_HYPOTHESIS + Max Length + + + SMESH_USE_PREESTIMATED_LENGTH + Use preestimated length + + + SMESH_MAX_LENGTH_TITLE + Hypothesis Construction + + + SMESH_MAX_ELEMENT_AREA_HYPOTHESIS + Max. Element Area + + + SMESH_MAX_ELEMENT_AREA_PARAM + Max. Area + + + SMESH_MAX_ELEMENT_AREA_TITLE + Hypothesis Construction + + + SMESH_MAX_ELEMENT_VOLUME_HYPOTHESIS + Max. Element Volume + + + SMESH_MAX_ELEMENT_VOLUME_PARAM + Max. Volume + + + SMESH_MAX_ELEMENT_VOLUME_TITLE + Hypothesis Construction + + + SMESH_NB_SEGMENTS_HYPOTHESIS + Number of Segments + + + SMESH_NB_SEGMENTS_PARAM + Number of Segments + + + SMESH_NB_SEGMENTS_SCALE_PARAM + Scale Factor + + + SMESH_NB_SEGMENTS_TITLE + Hypothesis Construction + + + SMESH_NO_CONV + No conversion + + + SMESH_NUMBER_OF_LAYERS + Number of Layers + + + SMESH_NUMBER_OF_LAYERS_HYPOTHESIS + Radial Prism Parameter + + + SMESH_NUMBER_OF_LAYERS_2D_HYPOTHESIS + Radial Quadrangle Parameter + + + SMESH_NUMBER_OF_LAYERS_TITLE + Hypothesis Construction + + + SMESH_NUMBER_OF_LAYERS_2D_TITLE + Hypothesis Construction + + + SMESH_PROJECTION_SOURCE_1D_HYPOTHESIS + Projection Source 1D + + + SMESH_PROJECTION_SOURCE_1D_TITLE + Hypothesis Construction + + + SMESH_PROJECTION_SOURCE_2D_HYPOTHESIS + Projection Source 2D + + + SMESH_PROJECTION_SOURCE_2D_TITLE + Hypothesis Construction + + + SMESH_PROJECTION_SOURCE_3D_HYPOTHESIS + Projection Source 3D + + + SMESH_PROJECTION_SOURCE_3D_TITLE + Hypothesis Construction + + + SMESH_IMPORT_SOURCE_1D_HYPOTHESIS + Source edges + + + SMESH_IMPORT_SOURCE_1D_TITLE + Hypothesis Construction + + + SMESH_IMPORT_SOURCE_2D_HYPOTHESIS + Source faces + + + SMESH_IMPORT_SOURCE_2D_TITLE + Hypothesis Construction + + + SMESH_REMOVE_ROW + Remove row + + + SMESH_REVERSED_EDGES + Reversed Edges + + + SMESH_FIXED_POINTS + Fixed Points + + + SMESH_RANGE + Range + + + SMESH_NB_SEGMENTS + Nb. Segments + + + SMESH_SAME_NB_SEGMENTS + Same Nb. Segments for All Intervals + + + SMESH_BASE_VERTEX + Base vertex + + + SMESH_SEGMENT_LENGTH_AROUND_VERTEX_HYPOTHESIS + Segment Length Around Vertex + + + SMESH_SEGMENT_LENGTH_AROUND_VERTEX_PARAM + Length + + + SMESH_SEGMENT_LENGTH_AROUND_VERTEX_TITLE + Hypothesis Construction + + + SMESH_SOURCE_3DSHAPE + 3D shape + + + SMESH_SOURCE_EDGE + Edge + + + SMESH_SOURCE_EDGES + Groups of Edges + + + SMESH_SOURCE_FACE + Face + + + SMESH_SOURCE_FACES + Groups of Faces + + + SMESH_SOURCE_MESH + Mesh + + + SMESH_COPY_MESH + To copy mesh + + + SMESH_TO_COPY_GROUPS + To copy groups + + + SMESH_SOURCE_VERTEX + Source Vertex + + + SMESH_SOURCE_VERTEX1 + Source Vertex 1 + + + SMESH_SOURCE_VERTEX2 + Source Vertex 2 + + + SMESH_START_END_LENGTH_HYPOTHESIS + Start and End local Length + + + SMESH_START_END_LENGTH_TITLE + Hypothesis Construction + + + SMESH_START_LENGTH_PARAM + Start Length + + + SMESH_TAB_FUNC + Table function + + + SMESH_TARGET_VERTEX + Target Vertex + + + SMESH_TARGET_VERTEX1 + Target Vertex 1 + + + SMESH_TARGET_VERTEX2 + Target Vertex 2 + + + SMESH_QUADRANGLE_PARAMS_HYPOTHESIS + Quadrangle parameters + + + SMESH_QUADRANGLE_PARAMS_TITLE + Hypothesis Construction + + + SMESH_QUAD_TYPE + Type + + + + StdMeshersGUI_QuadrangleParamWdg + + SMESH_QUAD_TYPE_0 + Standard + + + SMESH_QUAD_TYPE_1 + Triangle preference + + + SMESH_QUAD_TYPE_2 + Quadrangle preference + + + SMESH_QUAD_TYPE_3 + Quadrangle preference (reversed) + + + SMESH_QUAD_TYPE_4 + Reduced + + + + StdMeshersGUI_LayerDistributionParamWdg + + CHANGE_TYPE + Change Type + + + CREATE + Create + + + EDIT + Edit + + diff --git a/src/StdMeshersGUI/StdMeshers_msg_fr.ts b/src/StdMeshersGUI/StdMeshers_msg_fr.ts new file mode 100755 index 000000000..5f3e75f46 --- /dev/null +++ b/src/StdMeshersGUI/StdMeshers_msg_fr.ts @@ -0,0 +1,385 @@ + + + + + @default + + SMESH_ARITHMETIC_1D_HYPOTHESIS + Arithmétique 1D + + + SMESH_ARITHMETIC_1D_PARAM + Raison arithmétique + + + SMESH_ARITHMETIC_1D_TITLE + Construction de l'hypothèse + + + SMESH_AUTOMATIC_LENGTH_HYPOTHESIS + Longueur automatique + + + SMESH_AUTOMATIC_LENGTH_TITLE + Construction de l'hypothèse + + + SMESH_CONV_MODE + Mode de conversion + + + SMESH_CUT_NEG_MODE + Section négative + + + SMESH_DEFLECTION1D_HYPOTHESIS + Déflection 1D + + + SMESH_DEFLECTION1D_PARAM + Déflection + + + SMESH_DEFLECTION1D_TITLE + Construction de l'hypothèse + + + SMESH_DENSITY_FUNC + Fonction de densité + + + SMESH_DISTR + Distribution + + + SMESH_DISTR_EXPR + Distribution de densité analytique + + + SMESH_DISTR_REGULAR + Distribution équidistante + + + SMESH_DISTR_SCALE + Progression géométrique + + + SMESH_DISTR_TAB + Table de densités + + + SMESH_DISTR_TYPE + Type de distribution + + + SMESH_END_LENGTH_PARAM + Longueur finale + + + SMESH_EXPR_FUNC + Expression de la densité f(t) = + + + SMESH_EXP_MODE + Exposant + + + SMESH_FINENESS_PARAM + Finesse + + + SMESH_FUNC_DOMAIN + Avertissement: il faut définir la fonction sur le segment [0..1] + + + SMESH_INSERT_ROW + Insérer une ligne + + + SMESH_INVALID_FUNCTION + La fonction n'est pas valide + + + SMESH_LAYERS_DISTRIBUTION + Hypothèse 1D + + + SMESH_LAYER_DISTRIBUTION_HYPOTHESIS + Distribution des couches + + + SMESH_LAYER_DISTRIBUTION_TITLE + Construction de l'hypothèse + + + SMESH_LOCAL_LENGTH_HYPOTHESIS + Longueur moyennne + + + SMESH_LOCAL_LENGTH_PARAM + Longueur + + + SMESH_LOCAL_LENGTH_PRECISION + Précision + + + SMESH_LOCAL_LENGTH_TITLE + Construction de l'hypothèse + + + SMESH_FIXED_POINTS_1D_HYPOTHESIS + Points fixes 1D + + + SMESH_FIXED_POINTS_1D_TITLE + Construction de l'hypothèse + + + SMESH_MAX_LENGTH_HYPOTHESIS + Longueur maximale + + + SMESH_USE_PREESTIMATED_LENGTH + Utiliser la longueur pré-estimée + + + SMESH_MAX_LENGTH_TITLE + Construction de l'hypothèse + + + SMESH_MAX_ELEMENT_AREA_HYPOTHESIS + Aire maximale d'une maille + + + SMESH_MAX_ELEMENT_AREA_PARAM + Aire maximale + + + SMESH_MAX_ELEMENT_AREA_TITLE + Construction de l'hypothèse + + + SMESH_MAX_ELEMENT_VOLUME_HYPOTHESIS + Volume maximal d'une maille + + + SMESH_MAX_ELEMENT_VOLUME_PARAM + Volume maximal + + + SMESH_MAX_ELEMENT_VOLUME_TITLE + Construction de l'hypothèse + + + SMESH_NB_SEGMENTS_HYPOTHESIS + Nombre de segments + + + SMESH_NB_SEGMENTS_PARAM + Nombre de segments + + + SMESH_NB_SEGMENTS_SCALE_PARAM + Facteur d'échelle + + + SMESH_NB_SEGMENTS_TITLE + Construction de l'hypothèse + + + SMESH_NO_CONV + Sans conversion + + + SMESH_NUMBER_OF_LAYERS + Nombre de couches + + + SMESH_NUMBER_OF_LAYERS_HYPOTHESIS + Paramètre des prismes radiaux + + + SMESH_NUMBER_OF_LAYERS_2D_HYPOTHESIS + Paramètre des quadrangles radiaux + + + SMESH_NUMBER_OF_LAYERS_TITLE + Construction de l'hypothèse + + + SMESH_NUMBER_OF_LAYERS_2D_TITLE + Construction de l'hypothèse + + + SMESH_PROJECTION_SOURCE_1D_HYPOTHESIS + Source pour le projection 1D + + + SMESH_PROJECTION_SOURCE_1D_TITLE + Construction de l'hypothèse + + + SMESH_PROJECTION_SOURCE_2D_HYPOTHESIS + Source pour la projection 2D + + + SMESH_PROJECTION_SOURCE_2D_TITLE + Construction de l'hypothèse + + + SMESH_PROJECTION_SOURCE_3D_HYPOTHESIS + Source pour la projection 3D + + + SMESH_PROJECTION_SOURCE_3D_TITLE + Construction de l'hypothèse + + + SMESH_REMOVE_ROW + Supprimer une ligne + + + SMESH_REVERSED_EDGES + Arêtes inversées + + + SMESH_FIXED_POINTS + Points fixés + + + SMESH_RANGE + Intervalle + + + SMESH_NB_SEGMENTS + Nb. segments + + + SMESH_SAME_NB_SEGMENTS + Le même Nb. segments dans chaque intervalle + + + SMESH_BASE_VERTEX + Point de base + + + SMESH_SEGMENT_LENGTH_AROUND_VERTEX_HYPOTHESIS + Longueur des segments autour d'un point + + + SMESH_SEGMENT_LENGTH_AROUND_VERTEX_PARAM + Longueur + + + SMESH_SEGMENT_LENGTH_AROUND_VERTEX_TITLE + Construction de l'hypothèse + + + SMESH_SOURCE_3DSHAPE + Objet 3D + + + SMESH_SOURCE_EDGE + Arête + + + SMESH_SOURCE_FACE + Face + + + SMESH_SOURCE_MESH + Maillage + + + SMESH_SOURCE_VERTEX + Point source + + + SMESH_SOURCE_VERTEX1 + Point source 1 + + + SMESH_SOURCE_VERTEX2 + Point source 2 + + + SMESH_START_END_LENGTH_HYPOTHESIS + Start and end local Length + + + SMESH_START_END_LENGTH_TITLE + Construction de l'hypothèse + + + SMESH_START_LENGTH_PARAM + Longueur initiale + + + SMESH_TAB_FUNC + Table de valeurs de la fonction + + + SMESH_TARGET_VERTEX + Point cible + + + SMESH_TARGET_VERTEX1 + Point cible 1 + + + SMESH_TARGET_VERTEX2 + Point cible 2 + + + SMESH_QUADRANGLE_PARAMS_HYPOTHESIS + Paramètres pour le maillage quadrangulaire + + + SMESH_QUADRANGLE_PARAMS_TITLE + Construction de l'hypothèse + + + SMESH_QUAD_TYPE + Type + + + + StdMeshersGUI_QuadrangleParamWdg + + SMESH_QUAD_TYPE_0 + Standard + + + SMESH_QUAD_TYPE_1 + Triangles privilégiés + + + SMESH_QUAD_TYPE_2 + Quadrangles privilégiés + + + SMESH_QUAD_TYPE_3 + Quadrangles privilégiés (inversé) + + + SMESH_QUAD_TYPE_4 + Réduction + + + + StdMeshersGUI_LayerDistributionParamWdg + + CHANGE_TYPE + Changer le type + + + CREATE + Créer + + + EDIT + Editer + + + diff --git a/src/StdMeshers_I/Makefile.am b/src/StdMeshers_I/Makefile.am index 3331c0b36..17d7c9f6f 100644 --- a/src/StdMeshers_I/Makefile.am +++ b/src/StdMeshers_I/Makefile.am @@ -63,7 +63,11 @@ salomeinclude_HEADERS = \ StdMeshers_MaxLength_i.hxx \ StdMeshers_QuadrangleParams_i.hxx \ StdMeshers_RadialQuadrangle_1D2D_i.hxx \ - SMESH_StdMeshers_I.hxx + SMESH_StdMeshers_I.hxx \ + StdMeshers_ImportSource1D_i.hxx \ + StdMeshers_ImportSource2D_i.hxx \ + StdMeshers_Import_1D_i.hxx \ + StdMeshers_Import_1D2D_i.hxx # Libraries targets lib_LTLIBRARIES = libStdMeshersEngine.la @@ -105,7 +109,11 @@ dist_libStdMeshersEngine_la_SOURCES = \ StdMeshers_TrianglePreference_i.cxx \ StdMeshers_MaxLength_i.cxx \ StdMeshers_QuadrangleParams_i.cxx \ - StdMeshers_RadialQuadrangle_1D2D_i.cxx + StdMeshers_RadialQuadrangle_1D2D_i.cxx \ + StdMeshers_ImportSource1D_i.cxx \ + StdMeshers_ImportSource2D_i.cxx \ + StdMeshers_Import_1D_i.cxx \ + StdMeshers_Import_1D2D_i.cxx # additionnal information to compil and link file libStdMeshersEngine_la_CPPFLAGS = \ diff --git a/src/StdMeshers_I/StdMeshers_Deflection1D_i.cxx b/src/StdMeshers_I/StdMeshers_Deflection1D_i.cxx index 3c0859e23..61416d23c 100644 --- a/src/StdMeshers_I/StdMeshers_Deflection1D_i.cxx +++ b/src/StdMeshers_I/StdMeshers_Deflection1D_i.cxx @@ -25,7 +25,6 @@ // Moved here from SMESH_LocalLength_i.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #include "StdMeshers_Deflection1D_i.hxx" #include "SMESH_Gen_i.hxx" diff --git a/src/StdMeshers_I/StdMeshers_ImportSource1D_i.cxx b/src/StdMeshers_I/StdMeshers_ImportSource1D_i.cxx new file mode 100644 index 000000000..4d33ec8bb --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_ImportSource1D_i.cxx @@ -0,0 +1,280 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_ImportSource1D_i.cxx +// Module : SMESH +// +#include "StdMeshers_ImportSource1D_i.hxx" + +#include "SMESH_Gen.hxx" +#include "SMESH_Gen_i.hxx" +#include "SMESH_Group_i.hxx" +#include "SMESH_PythonDump.hxx" +#include "StdMeshers_ObjRefUlils.hxx" + +#include "Utils_CorbaException.hxx" +#include "utilities.h" + +#include + +#include CORBA_SERVER_HEADER(SMESH_Group) + +using namespace std; + +//============================================================================= +/*! + * StdMeshers_ImportSource1D_i::StdMeshers_ImportSource1D_i + * + * Constructor + */ +//============================================================================= + +StdMeshers_ImportSource1D_i::StdMeshers_ImportSource1D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ) +{ + MESSAGE( "StdMeshers_ImportSource1D_i::StdMeshers_ImportSource1D_i" ); + myBaseImpl = new ::StdMeshers_ImportSource1D( theGenImpl->GetANewId(), + theStudyId, + theGenImpl ); + _groupEntries = new SMESH::string_array(); +} + +//============================================================================= +/*! + * StdMeshers_ImportSource1D_i::~StdMeshers_ImportSource1D_i + * + * Destructor + */ +//============================================================================= + +StdMeshers_ImportSource1D_i::~StdMeshers_ImportSource1D_i() +{ + MESSAGE( "StdMeshers_ImportSource1D_i::~StdMeshers_ImportSource1D_i" ); +} + +//============================================================================= +/*! + * SetSourceEdges + */ +//============================================================================= + +void StdMeshers_ImportSource1D_i::SetSourceEdges(const SMESH::ListOfGroups& groups) +{ + MESSAGE( "StdMeshers_ImportSource1D_i::SetSourceEdges" ); + ASSERT( myBaseImpl ); + try + { + std::vector smesh_groups; + std::vector entries; + SALOMEDS::Study_var study = SMESH_Gen_i::GetSMESHGen()->GetCurrentStudy(); + for ( int i = 0; i < groups.length(); ++i ) + if ( SMESH_GroupBase_i* gp_i = SMESH::DownCast( groups[i] )) + { + if ( gp_i->GetType() != SMESH::EDGE ) + 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]); + if ( !so->_is_nil()) + { + CORBA::String_var entry = so->GetID(); + entries.push_back( entry.in() ); + } + } + this->GetImpl()->SetGroups( smesh_groups ); + + _groupEntries = new SMESH::string_array; + _groupEntries->length( entries.size ()); + for ( int i = 0; i < entries.size(); ++i ) + _groupEntries[i] = entries[i].c_str(); + } + catch ( SALOME_Exception& S_ex ) + { + THROW_SALOME_CORBA_EXCEPTION( S_ex.what(), SALOME::BAD_PARAM ); + } + + // Update Python script + SMESH::TPythonDump() << _this() << ".SetSourceEdges( " << groups << " )"; +} + +//============================================================================= +/*! + * Return entries of groups + */ +//============================================================================= + +SMESH::string_array* StdMeshers_ImportSource1D_i::GetSourceEdges() +{ + MESSAGE( "StdMeshers_ImportSource1D_i::GetImportSource" ); + SMESH::string_array_var res = new SMESH::string_array( _groupEntries ); + return res._retn(); +} + +//================================================================================ +/*! + * \brief Set to copy mesh and groups + */ +//================================================================================ + +void StdMeshers_ImportSource1D_i::SetCopySourceMesh(CORBA::Boolean toCopyMesh, + CORBA::Boolean toCopyGroups) +{ + GetImpl()->SetCopySourceMesh(toCopyMesh,toCopyGroups); + SMESH::TPythonDump() << _this() << ".SetCopySourceMesh( " + << toCopyMesh << ", " << toCopyGroups << " )"; +} + +//================================================================================ +/*! + * \brief Return "to copy mesh and groups" + */ +//================================================================================ + +void StdMeshers_ImportSource1D_i::GetCopySourceMesh(CORBA::Boolean& toCopyMesh, + CORBA::Boolean& toCopyGroups) +{ + GetImpl()->GetCopySourceMesh(toCopyMesh,toCopyGroups); +} + +//================================================================================ +/*! + * \brief Write parameters in a string + * \retval char* - resulting string + */ +//================================================================================ + +char* StdMeshers_ImportSource1D_i::SaveTo() +{ + std::ostringstream os; + os << " " << _groupEntries->length(); + + SALOMEDS::Study_var study = SMESH_Gen_i::GetSMESHGen()->GetCurrentStudy(); + for ( int i = 0; i < _groupEntries->length(); ++i ) + { + // entry + os << " " << _groupEntries[i]; + + // id + SALOMEDS::SObject_var groupSO = study->FindObjectID( _groupEntries[i] ); + CORBA::Object_var groupObj; + if ( !groupSO->_is_nil() ) + groupObj = groupSO->GetObject(); + StdMeshers_ObjRefUlils::SaveToStream( groupObj, os ); + } + + myBaseImpl->SaveTo( os ); + + return CORBA::string_dup( os.str().c_str() ); +} + +//================================================================================ +/*! + * \brief Retrieve parameters from the string + * \param theStream - the input string + */ +//================================================================================ + +void StdMeshers_ImportSource1D_i::LoadFrom( const char* theStream ) +{ + std::istringstream is( theStream ); + + int nbGroups; + is >> nbGroups; + + _groupEntries = new SMESH::string_array; + _groupEntries->length( nbGroups ); + std::string id, entry; + for ( int i = 0; i < _groupEntries->length(); ++i ) + { + if ( is >> entry ) + _groupEntries[i] = entry.c_str(); + else + { + _groupEntries->length( i ); + is.clear(ios::badbit | is.rdstate()); + break; + } + if ( is >> id ) + _groupIDs.push_back( id ); + else + { + is.clear(ios::badbit | is.rdstate()); + break; + } + } + + myBaseImpl->LoadFrom( is ); +} + +//================================================================================ +/*! + * \brief Retrieve groups by their ids loaded by LoadFrom() + * This is possible only when all meshes are fully loaded + */ +//================================================================================ + +void StdMeshers_ImportSource1D_i::UpdateAsMeshesRestored() +{ + std::vector smesh_groups; + for ( unsigned i = 0; i < _groupIDs.size(); ++i ) + { + std::istringstream is( _groupIDs[i].c_str() ); + SMESH::SMESH_GroupBase_var group = + StdMeshers_ObjRefUlils::LoadObjectFromStream( is ); + if ( SMESH_GroupBase_i* gp_i = SMESH::DownCast( group )) + smesh_groups.push_back( gp_i->GetSmeshGroup() ); + } + GetImpl()->RestoreGroups(smesh_groups); +} + +//============================================================================= +/*! + * StdMeshers_ImportSource1D_i::GetImpl + * + * Get implementation + */ +//============================================================================= + +::StdMeshers_ImportSource1D* StdMeshers_ImportSource1D_i::GetImpl() +{ + MESSAGE( "StdMeshers_ImportSource1D_i::GetImpl" ); + return ( ::StdMeshers_ImportSource1D* )myBaseImpl; +} + +//================================================================================ +/*! + * \brief Verify whether hypothesis supports given entity type + * \param type - dimension (see SMESH::Dimension enumeration) + * \retval CORBA::Boolean - TRUE if dimension is supported, FALSE otherwise + * + * Verify whether hypothesis supports given entity type (see SMESH::Dimension enumeration) + */ +//================================================================================ +CORBA::Boolean StdMeshers_ImportSource1D_i::IsDimSupported( SMESH::Dimension type ) +{ + return type == SMESH::DIM_1D; +} + diff --git a/src/StdMeshers_I/StdMeshers_ImportSource1D_i.hxx b/src/StdMeshers_I/StdMeshers_ImportSource1D_i.hxx new file mode 100644 index 000000000..216244a62 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_ImportSource1D_i.hxx @@ -0,0 +1,74 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_ImportSource1D_i.hxx +// Module : SMESH +// +#ifndef _SMESH_ImportSource1D_I_HXX_ +#define _SMESH_ImportSource1D_I_HXX_ + +#include "SMESH_StdMeshers_I.hxx" + +#include +#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) + +#include "SMESH_Hypothesis_i.hxx" +#include "StdMeshers_ImportSource.hxx" + +class SMESH_Gen; + +class STDMESHERS_I_EXPORT StdMeshers_ImportSource1D_i: + public virtual POA_StdMeshers::StdMeshers_ImportSource1D, + public virtual SMESH_Hypothesis_i +{ + public: + // Constructor + StdMeshers_ImportSource1D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~StdMeshers_ImportSource1D_i(); + + void SetSourceEdges(const ::SMESH::ListOfGroups& groups); + SMESH::string_array* GetSourceEdges(); + void SetCopySourceMesh(::CORBA::Boolean toCopyMesh, ::CORBA::Boolean toCopyGroups); + void GetCopySourceMesh(::CORBA::Boolean& toCopyMesh, ::CORBA::Boolean& toCopyGroups); + + // Get implementation + ::StdMeshers_ImportSource1D* GetImpl(); + + // Verify whether hypothesis supports given entity type + CORBA::Boolean IsDimSupported( SMESH::Dimension type ); + + // Redefined Persistence + virtual char* SaveTo(); + virtual void LoadFrom( const char* theStream ); + virtual void UpdateAsMeshesRestored(); + + private: + SMESH::string_array_var _groupEntries; + std::vector< std::string > _groupIDs; +}; + +#endif + diff --git a/src/StdMeshers_I/StdMeshers_ImportSource2D_i.cxx b/src/StdMeshers_I/StdMeshers_ImportSource2D_i.cxx new file mode 100644 index 000000000..b2221a426 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_ImportSource2D_i.cxx @@ -0,0 +1,280 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_ImportSource2D_i.cxx +// Module : SMESH +// +#include "StdMeshers_ImportSource2D_i.hxx" + +#include "SMESH_Gen.hxx" +#include "SMESH_Gen_i.hxx" +#include "SMESH_Group_i.hxx" +#include "SMESH_PythonDump.hxx" +#include "StdMeshers_ObjRefUlils.hxx" + +#include "Utils_CorbaException.hxx" +#include "utilities.h" + +#include + +#include CORBA_SERVER_HEADER(SMESH_Group) + +using namespace std; + +//============================================================================= +/*! + * StdMeshers_ImportSource2D_i::StdMeshers_ImportSource2D_i + * + * Constructor + */ +//============================================================================= + +StdMeshers_ImportSource2D_i::StdMeshers_ImportSource2D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ) +{ + MESSAGE( "StdMeshers_ImportSource2D_i::StdMeshers_ImportSource2D_i" ); + myBaseImpl = new ::StdMeshers_ImportSource2D( theGenImpl->GetANewId(), + theStudyId, + theGenImpl ); + _groupEntries = new SMESH::string_array(); +} + +//============================================================================= +/*! + * StdMeshers_ImportSource2D_i::~StdMeshers_ImportSource2D_i + * + * Destructor + */ +//============================================================================= + +StdMeshers_ImportSource2D_i::~StdMeshers_ImportSource2D_i() +{ + MESSAGE( "StdMeshers_ImportSource2D_i::~StdMeshers_ImportSource2D_i" ); +} + +//============================================================================= +/*! + * SetSourceFaces + */ +//============================================================================= + +void StdMeshers_ImportSource2D_i::SetSourceFaces(const SMESH::ListOfGroups& groups) +{ + MESSAGE( "StdMeshers_ImportSource2D_i::SetSourceFaces" ); + ASSERT( myBaseImpl ); + try + { + std::vector smesh_groups; + std::vector entries; + SALOMEDS::Study_var study = SMESH_Gen_i::GetSMESHGen()->GetCurrentStudy(); + for ( int i = 0; i < groups.length(); ++i ) + if ( SMESH_GroupBase_i* gp_i = SMESH::DownCast( groups[i] )) + { + if ( gp_i->GetType() != SMESH::FACE ) + 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]); + if ( !so->_is_nil()) + { + CORBA::String_var entry = so->GetID(); + entries.push_back( entry.in() ); + } + } + this->GetImpl()->SetGroups( smesh_groups ); + + _groupEntries = new SMESH::string_array; + _groupEntries->length( entries.size ()); + for ( int i = 0; i < entries.size(); ++i ) + _groupEntries[i] = entries[i].c_str(); + } + catch ( SALOME_Exception& S_ex ) + { + THROW_SALOME_CORBA_EXCEPTION( S_ex.what(), SALOME::BAD_PARAM ); + } + + // Update Python script + SMESH::TPythonDump() << _this() << ".SetSourceFaces( " << groups << " )"; +} + +//============================================================================= +/*! + * Return entries of groups + */ +//============================================================================= + +SMESH::string_array* StdMeshers_ImportSource2D_i::GetSourceFaces() +{ + MESSAGE( "StdMeshers_ImportSource2D_i::GetImportSource" ); + SMESH::string_array_var res = new SMESH::string_array( _groupEntries ); + return res._retn(); +} + +//================================================================================ +/*! + * \brief Set to copy mesh and groups + */ +//================================================================================ + +void StdMeshers_ImportSource2D_i::SetCopySourceMesh(CORBA::Boolean toCopyMesh, + CORBA::Boolean toCopyGroups) +{ + GetImpl()->SetCopySourceMesh(toCopyMesh,toCopyGroups); + SMESH::TPythonDump() << _this() << ".SetCopySourceMesh( " + << toCopyMesh << ", " << toCopyGroups << " )"; +} + +//================================================================================ +/*! + * \brief Return "to copy mesh and groups" + */ +//================================================================================ + +void StdMeshers_ImportSource2D_i::GetCopySourceMesh(CORBA::Boolean& toCopyMesh, + CORBA::Boolean& toCopyGroups) +{ + GetImpl()->GetCopySourceMesh(toCopyMesh,toCopyGroups); +} + +//================================================================================ +/*! + * \brief Write parameters in a string + * \retval char* - resulting string + */ +//================================================================================ + +char* StdMeshers_ImportSource2D_i::SaveTo() +{ + std::ostringstream os; + os << " " << _groupEntries->length(); + + SALOMEDS::Study_var study = SMESH_Gen_i::GetSMESHGen()->GetCurrentStudy(); + for ( int i = 0; i < _groupEntries->length(); ++i ) + { + // entry + os << " " << _groupEntries[i]; + + // id + SALOMEDS::SObject_var groupSO = study->FindObjectID( _groupEntries[i] ); + CORBA::Object_var groupObj; + if ( !groupSO->_is_nil() ) + groupObj = groupSO->GetObject(); + StdMeshers_ObjRefUlils::SaveToStream( groupObj, os ); + } + + myBaseImpl->SaveTo( os ); + + return CORBA::string_dup( os.str().c_str() ); +} + +//================================================================================ +/*! + * \brief Retrieve parameters from the string + * \param theStream - the input string + */ +//================================================================================ + +void StdMeshers_ImportSource2D_i::LoadFrom( const char* theStream ) +{ + std::istringstream is( theStream ); + + int nbGroups; + is >> nbGroups; + + _groupEntries = new SMESH::string_array; + _groupEntries->length( nbGroups ); + std::string id, entry; + for ( int i = 0; i < _groupEntries->length(); ++i ) + { + if ( is >> entry ) + _groupEntries[i] = entry.c_str(); + else + { + _groupEntries->length( i ); + is.clear(ios::badbit | is.rdstate()); + break; + } + if ( is >> id ) + _groupIDs.push_back( id ); + else + { + is.clear(ios::badbit | is.rdstate()); + break; + } + } + + myBaseImpl->LoadFrom( is ); +} + +//================================================================================ +/*! + * \brief Retrieve groups by their ids loaded by LoadFrom() + * This is possible only when all meshes are fully loaded + */ +//================================================================================ + +void StdMeshers_ImportSource2D_i::UpdateAsMeshesRestored() +{ + std::vector smesh_groups; + for ( unsigned i = 0; i < _groupIDs.size(); ++i ) + { + std::istringstream is( _groupIDs[i].c_str() ); + SMESH::SMESH_GroupBase_var group = + StdMeshers_ObjRefUlils::LoadObjectFromStream( is ); + if ( SMESH_GroupBase_i* gp_i = SMESH::DownCast( group )) + smesh_groups.push_back( gp_i->GetSmeshGroup() ); + } + GetImpl()->RestoreGroups(smesh_groups); +} + +//============================================================================= +/*! + * StdMeshers_ImportSource2D_i::GetImpl + * + * Get implementation + */ +//============================================================================= + +::StdMeshers_ImportSource2D* StdMeshers_ImportSource2D_i::GetImpl() +{ + MESSAGE( "StdMeshers_ImportSource2D_i::GetImpl" ); + return ( ::StdMeshers_ImportSource2D* )myBaseImpl; +} + +//================================================================================ +/*! + * \brief Verify whether hypothesis supports given entity type + * \param type - dimension (see SMESH::Dimension enumeration) + * \retval CORBA::Boolean - TRUE if dimension is supported, FALSE otherwise + * + * Verify whether hypothesis supports given entity type (see SMESH::Dimension enumeration) + */ +//================================================================================ +CORBA::Boolean StdMeshers_ImportSource2D_i::IsDimSupported( SMESH::Dimension type ) +{ + return type == SMESH::DIM_2D; +} + diff --git a/src/StdMeshers_I/StdMeshers_ImportSource2D_i.hxx b/src/StdMeshers_I/StdMeshers_ImportSource2D_i.hxx new file mode 100644 index 000000000..7f2d71217 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_ImportSource2D_i.hxx @@ -0,0 +1,74 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_ImportSource2D_i.hxx +// Module : SMESH +// +#ifndef _SMESH_ImportSource2D_I_HXX_ +#define _SMESH_ImportSource2D_I_HXX_ + +#include "SMESH_StdMeshers_I.hxx" + +#include +#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) + +#include "SMESH_Hypothesis_i.hxx" +#include "StdMeshers_ImportSource.hxx" + +class SMESH_Gen; + +class STDMESHERS_I_EXPORT StdMeshers_ImportSource2D_i: + public virtual POA_StdMeshers::StdMeshers_ImportSource2D, + public virtual SMESH_Hypothesis_i +{ + public: + // Constructor + StdMeshers_ImportSource2D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~StdMeshers_ImportSource2D_i(); + + void SetSourceFaces(const ::SMESH::ListOfGroups& groups); + SMESH::string_array* GetSourceFaces(); + void SetCopySourceMesh(::CORBA::Boolean toCopyMesh, ::CORBA::Boolean toCopyGroups); + void GetCopySourceMesh(::CORBA::Boolean& toCopyMesh, ::CORBA::Boolean& toCopyGroups); + + // Get implementation + ::StdMeshers_ImportSource2D* GetImpl(); + + // Verify whether hypothesis supports given entity type + CORBA::Boolean IsDimSupported( SMESH::Dimension type ); + + // Redefined Persistence + virtual char* SaveTo(); + virtual void LoadFrom( const char* theStream ); + virtual void UpdateAsMeshesRestored(); + + private: + SMESH::string_array_var _groupEntries; + std::vector< std::string > _groupIDs; +}; + +#endif + diff --git a/src/StdMeshers_I/StdMeshers_Import_1D2D_i.cxx b/src/StdMeshers_I/StdMeshers_Import_1D2D_i.cxx new file mode 100644 index 000000000..e2489e54d --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_Import_1D2D_i.cxx @@ -0,0 +1,67 @@ +// Copyright (C) 2007-2010 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 +// + +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_Import_1D2D_i.cxx +// Module : SMESH +// +#include "StdMeshers_Import_1D2D_i.hxx" +#include "SMESH_Gen.hxx" + +#include "Utils_CorbaException.hxx" +#include "utilities.h" + +using namespace std; + + +//============================================================================= +/*! + * StdMeshers_Import_1D2D_i::StdMeshers_Import_1D2D_i + */ +//============================================================================= + +StdMeshers_Import_1D2D_i::StdMeshers_Import_1D2D_i (PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ), + SMESH_Algo_i( thePOA ), + SMESH_2D_Algo_i( thePOA ) +{ + MESSAGE( "StdMeshers_Import_1D2D_i::StdMeshers_Import_1D2D_i" ); + myBaseImpl = new ::StdMeshers_Import_1D2D(theGenImpl->GetANewId(), + theStudyId, + theGenImpl ); +} + +//----------------------------------------------------------------------------- + +StdMeshers_Import_1D2D_i::~StdMeshers_Import_1D2D_i() +{ + MESSAGE( "StdMeshers_Import_1D2D_i::~StdMeshers_Import_1D2D_i" ); +} + +//----------------------------------------------------------------------------- + +::StdMeshers_Import_1D2D* StdMeshers_Import_1D2D_i::GetImpl() +{ + MESSAGE( "StdMeshers_Import_1D2D_i::GetImpl" ); + return ( ::StdMeshers_Import_1D2D* )myBaseImpl; +} + diff --git a/src/StdMeshers_I/StdMeshers_Import_1D2D_i.hxx b/src/StdMeshers_I/StdMeshers_Import_1D2D_i.hxx new file mode 100644 index 000000000..8e569661c --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_Import_1D2D_i.hxx @@ -0,0 +1,53 @@ +// Copyright (C) 2007-2010 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 +// + +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_Import_1D2D_i.hxx +// Module : SMESH +// +#ifndef _SMESH_Import_1D2D_I_HXX_ +#define _SMESH_Import_1D2D_I_HXX_ + +#include +#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) + +#include "SMESH_2D_Algo_i.hxx" +#include "StdMeshers_Import_1D2D.hxx" + +class SMESH_Gen; + +class StdMeshers_Import_1D2D_i: + public virtual POA_StdMeshers::StdMeshers_Import_1D2D, + public virtual SMESH_2D_Algo_i +{ +public: + // Constructor + StdMeshers_Import_1D2D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + + // Destructor + virtual ~StdMeshers_Import_1D2D_i(); + + // Get implementation + ::StdMeshers_Import_1D2D* GetImpl(); +}; + + +#endif diff --git a/src/StdMeshers_I/StdMeshers_Import_1D_i.cxx b/src/StdMeshers_I/StdMeshers_Import_1D_i.cxx new file mode 100644 index 000000000..02b3e2951 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_Import_1D_i.cxx @@ -0,0 +1,85 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_Import_1D_i.cxx +// Moved here from SMESH_Import_1D_i.cxx +// Author : Paul RASCLE, EDF +// Module : SMESH +// +#include "StdMeshers_Import_1D_i.hxx" +#include "SMESH_Gen.hxx" + +#include "Utils_CorbaException.hxx" +#include "utilities.h" + +using namespace std; + +//============================================================================= +/*! + * StdMeshers_Import_1D_i::StdMeshers_Import_1D_i + * + * Constructor + */ +//============================================================================= + +StdMeshers_Import_1D_i::StdMeshers_Import_1D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ), + SMESH_Algo_i( thePOA ), + SMESH_1D_Algo_i( thePOA ) +{ + MESSAGE( "StdMeshers_Import_1D_i::StdMeshers_Import_1D_i" ); + myBaseImpl = new ::StdMeshers_Import_1D( theGenImpl->GetANewId(), + theStudyId, + theGenImpl ); +} + +//============================================================================= +/*! + * StdMeshers_Import_1D_i::~StdMeshers_Import_1D_i + * + * Destructor + */ +//============================================================================= + +StdMeshers_Import_1D_i::~StdMeshers_Import_1D_i() +{ + MESSAGE( "StdMeshers_Import_1D_i::~StdMeshers_Import_1D_i" ); +} + +//============================================================================= +/*! + * StdMeshers_Import_1D_i::GetImpl + * + * Get implementation + */ +//============================================================================= + +::StdMeshers_Import_1D* StdMeshers_Import_1D_i::GetImpl() +{ + MESSAGE( "StdMeshers_Import_1D_i::GetImpl" ); + return ( ::StdMeshers_Import_1D* )myBaseImpl; +} + diff --git a/src/StdMeshers_I/StdMeshers_Import_1D_i.hxx b/src/StdMeshers_I/StdMeshers_Import_1D_i.hxx new file mode 100644 index 000000000..d0e1d9752 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_Import_1D_i.hxx @@ -0,0 +1,54 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_Import_1D_i.hxx +// Module : SMESH +// +#ifndef _SMESH_Import_1D_I_HXX_ +#define _SMESH_Import_1D_I_HXX_ + +#include "SMESH_StdMeshers_I.hxx" + +#include +#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) + +#include "SMESH_1D_Algo_i.hxx" +#include "StdMeshers_Import_1D.hxx" + +class STDMESHERS_I_EXPORT StdMeshers_Import_1D_i: + public virtual POA_StdMeshers::StdMeshers_Import_1D, + public virtual SMESH_1D_Algo_i +{ + public: + // Constructor + StdMeshers_Import_1D_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~StdMeshers_Import_1D_i(); + + // Get implementation + ::StdMeshers_Import_1D* GetImpl(); +}; + +#endif diff --git a/src/StdMeshers_I/StdMeshers_ProjectionSource1D_i.hxx b/src/StdMeshers_I/StdMeshers_ProjectionSource1D_i.hxx index d416a5787..fbd8b1898 100644 --- a/src/StdMeshers_I/StdMeshers_ProjectionSource1D_i.hxx +++ b/src/StdMeshers_I/StdMeshers_ProjectionSource1D_i.hxx @@ -24,7 +24,6 @@ // File : StdMeshers_ProjectionSource1D_i.hxx // Author : Edward AGAPOV // Module : SMESH -// $Header$ // #ifndef _SMESH_ProjectionSource1D_I_HXX_ #define _SMESH_ProjectionSource1D_I_HXX_ diff --git a/src/StdMeshers_I/StdMeshers_QuadrangleParams_i.cxx b/src/StdMeshers_I/StdMeshers_QuadrangleParams_i.cxx index 612ccc9ee..85295c055 100644 --- a/src/StdMeshers_I/StdMeshers_QuadrangleParams_i.cxx +++ b/src/StdMeshers_I/StdMeshers_QuadrangleParams_i.cxx @@ -16,13 +16,11 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // - // SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_QuadrangleParams_i.cxx // Author : Sergey KUUL, OCC // Module : SMESH -// $Header$ -// + #include "StdMeshers_QuadrangleParams_i.hxx" #include "SMESH_Gen_i.hxx" #include "SMESH_Gen.hxx" @@ -94,6 +92,21 @@ void StdMeshers_QuadrangleParams_i::SetTriaVertex(CORBA::Long vertID) << vertID << " )"; } +//============================================================================= +/*! + * StdMeshers_QuadrangleParams_i::GetTriaVertex + * + * Get base vertex for triangles + */ +//============================================================================= + +CORBA::Long StdMeshers_QuadrangleParams_i::GetTriaVertex() +{ + MESSAGE( "StdMeshers_QuadrangleParams_i::GetTriaVertex" ); + ASSERT( myBaseImpl ); + return this->GetImpl()->GetTriaVertex(); +} + //============================================================================= /*! * StdMeshers_QuadrangleParams_i::SetObjectEntry @@ -143,17 +156,65 @@ char* StdMeshers_QuadrangleParams_i::GetObjectEntry() //============================================================================= /*! - * StdMeshers_QuadrangleParams_i::GetTriaVertex + * StdMeshers_QuadrangleParams_i::SetQuadType * - * Get base vertex for triangles + * Set the type of quadrangulation */ //============================================================================= +void StdMeshers_QuadrangleParams_i::SetQuadType(StdMeshers::QuadType type) +{ + //static char* quadTypes[5] = {"StdMeshers.QUAD_STANDARD", + // "StdMeshers.QUAD_TRIANGLE_PREF", + // "StdMeshers.QUAD_QUADRANGLE_PREF", + // "StdMeshers.QUAD_QUADRANGLE_PREF_REVERSED", + // "StdMeshers.QUAD_REDUCED"}; -CORBA::Long StdMeshers_QuadrangleParams_i::GetTriaVertex() + MESSAGE("StdMeshers_QuadrangleParams_i::SetQuadType"); + ASSERT(myBaseImpl); + + if (int(type) >= int(StdMeshers::QUAD_NB_TYPES)) { + THROW_SALOME_CORBA_EXCEPTION("Bad type of quadrangulation", SALOME::BAD_PARAM); + } + + try { + this->GetImpl()->SetQuadType(StdMeshers_QuadType(int(type))); + } + catch (SALOME_Exception& S_ex) { + THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM); + } + + // Update Python script + const char* quadType; + switch (type) { + case StdMeshers::QUAD_STANDARD: + quadType = "StdMeshers.QUAD_STANDARD"; break; + case StdMeshers::QUAD_TRIANGLE_PREF: + quadType = "StdMeshers.QUAD_TRIANGLE_PREF"; break; + case StdMeshers::QUAD_QUADRANGLE_PREF: + quadType = "StdMeshers.QUAD_QUADRANGLE_PREF"; break; + case StdMeshers::QUAD_QUADRANGLE_PREF_REVERSED: + quadType = "StdMeshers.QUAD_QUADRANGLE_PREF_REVERSED"; break; + case StdMeshers::QUAD_REDUCED: + quadType = "StdMeshers.QUAD_REDUCED"; break; + default: + quadType = "UNKNOWN"; + } + SMESH::TPythonDump() << _this() << ".SetQuadType( " << quadType << " )"; + //SMESH::TPythonDump() << _this() << ".SetQuadType( " << quadTypes[int(type)] << " )"; +} + +//============================================================================= +/*! + * StdMeshers_QuadrangleParams_i::GetQuadType + * + * Get the type of quadrangulation + */ +//============================================================================= +StdMeshers::QuadType StdMeshers_QuadrangleParams_i::GetQuadType() { - MESSAGE( "StdMeshers_QuadrangleParams_i::GetTriaVertex" ); - ASSERT( myBaseImpl ); - return this->GetImpl()->GetTriaVertex(); + MESSAGE("StdMeshers_QuadrangleParams_i::GetQuadType"); + ASSERT(myBaseImpl); + return StdMeshers::QuadType(int(this->GetImpl()->GetQuadType())); } //============================================================================= @@ -183,4 +244,3 @@ CORBA::Boolean StdMeshers_QuadrangleParams_i::IsDimSupported( SMESH::Dimension t { return type == SMESH::DIM_2D; } - diff --git a/src/StdMeshers_I/StdMeshers_QuadrangleParams_i.hxx b/src/StdMeshers_I/StdMeshers_QuadrangleParams_i.hxx index fa695107d..062af680d 100644 --- a/src/StdMeshers_I/StdMeshers_QuadrangleParams_i.hxx +++ b/src/StdMeshers_I/StdMeshers_QuadrangleParams_i.hxx @@ -16,13 +16,12 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // - -// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's classes // File : StdMeshers_QuadrangleParams_i.hxx // Author : Sergey KUUL, OCC // Module : SMESH // $Header$ -// + #ifndef _SMESH_QUADRANGLEPARAMS_I_HXX_ #define _SMESH_QUADRANGLEPARAMS_I_HXX_ @@ -43,9 +42,9 @@ class STDMESHERS_I_EXPORT StdMeshers_QuadrangleParams_i: { public: // Constructor - StdMeshers_QuadrangleParams_i( PortableServer::POA_ptr thePOA, + StdMeshers_QuadrangleParams_i (PortableServer::POA_ptr thePOA, int theStudyId, - ::SMESH_Gen* theGenImpl ); + ::SMESH_Gen* theGenImpl); // Destructor virtual ~StdMeshers_QuadrangleParams_i(); @@ -56,18 +55,24 @@ public: // Get length //CORBA::Double GetLength(CORBA::Boolean theIsStart); - //Set base vertex for triangles - void SetTriaVertex(CORBA::Long vertID); + // Set base vertex for triangles + void SetTriaVertex (CORBA::Long vertID); - //Get base vertex for triangles + // Get base vertex for triangles CORBA::Long GetTriaVertex(); - //Set the Entry of the Object - void SetObjectEntry(const char* theEntry); + // Set the Entry of the Object + void SetObjectEntry (const char* theEntry); - //Get Object Entry + // Get Object Entry char* GetObjectEntry(); + // Set the type of quadrangulation + void SetQuadType (StdMeshers::QuadType type); + + // Get the type of quadrangulation + StdMeshers::QuadType GetQuadType(); + // Get implementation ::StdMeshers_QuadrangleParams* GetImpl(); diff --git a/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.cxx b/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.cxx index 090e00ee9..b58d9cbd5 100644 --- a/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.cxx +++ b/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.cxx @@ -19,7 +19,6 @@ // SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_RadialQuadrangle_1D2D_i.cxx -// Author : Paul RASCLE, EDF // Module : SMESH // #include "StdMeshers_RadialQuadrangle_1D2D_i.hxx" diff --git a/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.hxx b/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.hxx index 85a6e3ae0..1a9fb637c 100644 --- a/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.hxx +++ b/src/StdMeshers_I/StdMeshers_RadialQuadrangle_1D2D_i.hxx @@ -19,9 +19,7 @@ // SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_RadialQuadrangle_1D2D_i.hxx -// Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #ifndef _SMESH_RadialQuadrangle_1D2D_I_HXX_ #define _SMESH_RadialQuadrangle_1D2D_I_HXX_ diff --git a/src/StdMeshers_I/StdMeshers_Regular_1D_i.cxx b/src/StdMeshers_I/StdMeshers_Regular_1D_i.cxx index 2b75cdc8a..d6fd3cf45 100644 --- a/src/StdMeshers_I/StdMeshers_Regular_1D_i.cxx +++ b/src/StdMeshers_I/StdMeshers_Regular_1D_i.cxx @@ -25,7 +25,6 @@ // Moved here from SMESH_Regular_1D_i.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #include "StdMeshers_Regular_1D_i.hxx" #include "SMESH_Gen.hxx" diff --git a/src/StdMeshers_I/StdMeshers_Regular_1D_i.hxx b/src/StdMeshers_I/StdMeshers_Regular_1D_i.hxx index bfc463de5..02006c455 100644 --- a/src/StdMeshers_I/StdMeshers_Regular_1D_i.hxx +++ b/src/StdMeshers_I/StdMeshers_Regular_1D_i.hxx @@ -25,7 +25,6 @@ // Moved here from SMESH_Regular_1D_i.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #ifndef _SMESH_REGULAR_1D_I_HXX_ #define _SMESH_REGULAR_1D_I_HXX_ diff --git a/src/StdMeshers_I/StdMeshers_i.cxx b/src/StdMeshers_I/StdMeshers_i.cxx index f50fae594..a8f6a9824 100644 --- a/src/StdMeshers_I/StdMeshers_i.cxx +++ b/src/StdMeshers_I/StdMeshers_i.cxx @@ -56,6 +56,8 @@ #include "StdMeshers_SegmentLengthAroundVertex_i.hxx" #include "StdMeshers_MaxLength_i.hxx" #include "StdMeshers_QuadrangleParams_i.hxx" +#include "StdMeshers_ImportSource1D_i.hxx" +#include "StdMeshers_ImportSource2D_i.hxx" #include "StdMeshers_Regular_1D_i.hxx" #include "StdMeshers_MEFISTO_2D_i.hxx" @@ -67,6 +69,8 @@ #include "StdMeshers_CompositeSegment_1D_i.hxx" #include "StdMeshers_UseExisting_1D2D_i.hxx" #include "StdMeshers_RadialQuadrangle_1D2D_i.hxx" +#include "StdMeshers_Import_1D_i.hxx" +#include "StdMeshers_Import_1D2D_i.hxx" template class StdHypothesisCreator_i:public HypothesisCreator_i @@ -141,6 +145,10 @@ STDMESHERS_I_EXPORT aCreator = new StdHypothesisCreator_i; else if (strcmp(aHypName, "QuadrangleParams") == 0) aCreator = new StdHypothesisCreator_i; + else if (strcmp(aHypName, "ImportSource1D") == 0) + aCreator = new StdHypothesisCreator_i; + else if (strcmp(aHypName, "ImportSource2D") == 0) + aCreator = new StdHypothesisCreator_i; // Algorithms else if (strcmp(aHypName, "Regular_1D") == 0) @@ -171,6 +179,10 @@ STDMESHERS_I_EXPORT aCreator = new StdHypothesisCreator_i; else if (strcmp(aHypName, "RadialQuadrangle_1D2D") == 0) aCreator = new StdHypothesisCreator_i; + else if (strcmp(aHypName, "Import_1D") == 0) + aCreator = new StdHypothesisCreator_i; + else if (strcmp(aHypName, "Import_1D2D") == 0) + aCreator = new StdHypothesisCreator_i; else ; return aCreator; -- 2.30.2