diff --git a/idl/SMESH_Gen.idl b/idl/SMESH_Gen.idl index e9b678031..010525eaf 100644 --- a/idl/SMESH_Gen.idl +++ b/idl/SMESH_Gen.idl @@ -286,7 +286,7 @@ module SMESH raises ( SALOME::SALOME_Exception ); /*! * Create a dual mesh of a Tetrahedron mesh - * \param meshPart - TetraHedron mesh to create dual from + * \param mesh - TetraHedron mesh to create dual from * \param meshName - a name of the new mesh */ SMESH_Mesh CreateDualMesh(in SMESH_IDSource mesh, diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index 8f5bdb415..b2be7d8b8 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -60,6 +60,7 @@ SET(SMESH_RESOURCES_FILES mesh_conv_to_quad.png mesh_cutGroups.png mesh_cutquad.png + mesh_create_dual_mesh.png mesh_deflection.png mesh_deleteGroups.png mesh_diagonal.png diff --git a/resources/mesh_create_dual_mesh.png b/resources/mesh_create_dual_mesh.png new file mode 100644 index 000000000..d7a7be370 Binary files /dev/null and b/resources/mesh_create_dual_mesh.png differ diff --git a/src/SMESHGUI/SMESHGUI.cxx b/src/SMESHGUI/SMESHGUI.cxx index e57f7ea4d..0b0512b68 100644 --- a/src/SMESHGUI/SMESHGUI.cxx +++ b/src/SMESHGUI/SMESHGUI.cxx @@ -4415,6 +4415,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( SMESHOp::OpEditMeshOrSubMesh, meshId, -1 ); createMenu( SMESHOp::OpBuildCompoundMesh, meshId, -1 ); createMenu( SMESHOp::OpCopyMesh, meshId, -1 ); + createMenu( SMESHOp::OpCreateDualMesh, meshId, -1 ); createMenu( separator(), meshId, -1 ); createMenu( SMESHOp::OpCompute, meshId, -1 ); createMenu( SMESHOp::OpPreCompute, meshId, -1 ); @@ -4528,7 +4529,6 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( SMESHOp::OpConvertMeshToQuadratic, modifyId, -1 ); createMenu( SMESHOp::OpCreateBoundaryElements, modifyId, -1 ); - createMenu( SMESHOp::OpCreateDualMesh, modifyId, -1 ); createMenu( SMESHOp::OpExtrusion, modifyId, -1 ); createMenu( SMESHOp::OpExtrusionAlongAPath, modifyId, -1 ); createMenu( SMESHOp::OpRevolution, modifyId, -1 ); @@ -4680,7 +4680,6 @@ void SMESHGUI::initialize( CAM_Application* app ) int modifyTb = createTool( tr( "TB_MODIFY" ), QString( "SMESHModificationToolbar" ) ) ; createTool( SMESHOp::OpConvertMeshToQuadratic, modifyTb ); - createTool( SMESHOp::OpCreateDualMesh, modifyTb ); createTool( SMESHOp::OpCreateBoundaryElements, modifyTb ); createTool( SMESHOp::OpExtrusion, modifyTb ); createTool( SMESHOp::OpExtrusionAlongAPath, modifyTb ); @@ -4794,7 +4793,6 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->insert( separator(), -1, 0 ); createPopupItem( SMESHOp::OpConvertMeshToQuadratic, OB, mesh_submesh, "&& " + hasElems ); createPopupItem( SMESHOp::OpCreateBoundaryElements, OB, mesh_group, "&& selcount=1 && dim>=2"); - createPopupItem( SMESHOp::OpCreateDualMesh, OB, mesh_submesh, "&& selcount=1 && dim>=2"); // Adaptation - begin popupMgr()->insert( separator(), -1, 0 ); diff --git a/src/SMESHGUI/SMESHGUI_CreateDualMeshDlg.cxx b/src/SMESHGUI/SMESHGUI_CreateDualMeshDlg.cxx index 614220058..da67de1aa 100644 --- a/src/SMESHGUI/SMESHGUI_CreateDualMeshDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_CreateDualMeshDlg.cxx @@ -39,6 +39,7 @@ #include #include #include +#include #define SPACING 6 #define MARGIN 11 @@ -54,6 +55,12 @@ SMESHGUI_CreateDualMeshDlg::SMESHGUI_CreateDualMeshDlg() setObjectPixmap( "SMESH", tr( "ICON_SELECT" ) ); createObject( tr( "MESH" ), mainFrame(), 0 ); + myMeshNameLabel = new QLabel(QString(tr("DUAL_MESH_NAME")), mainFrame()); + myMeshName = new QLineEdit(mainFrame()); + + myProjShape = new QCheckBox(QString(tr("PROJ_SHAPE")), mainFrame()); + myProjShape->toggle(); + myWarning = new QLabel(QString("%1").arg(tr("NON_TETRA_MESH_WARNING")), mainFrame()); // Fill layout @@ -65,6 +72,9 @@ SMESHGUI_CreateDualMeshDlg::SMESHGUI_CreateDualMeshDlg() aLay->addWidget( objectWg( 0, Btn ), 0, 1 ); aLay->addWidget( objectWg( 0, Control ), 0, 2 ); aLay->addWidget( myWarning, 3, 0, 1, 3 ); + aLay->addWidget( myMeshNameLabel, 1, 0 ); + aLay->addWidget( myMeshName, 1, 2 ); + aLay->addWidget( myProjShape, 2, 0 ); } diff --git a/src/SMESHGUI/SMESHGUI_CreateDualMeshDlg.h b/src/SMESHGUI/SMESHGUI_CreateDualMeshDlg.h index e5096b237..83b2a959c 100644 --- a/src/SMESHGUI/SMESHGUI_CreateDualMeshDlg.h +++ b/src/SMESHGUI/SMESHGUI_CreateDualMeshDlg.h @@ -37,6 +37,7 @@ class QRadioButton; class QButtonGroup; class QGroupBox; class QLabel; +class QLineEdit; class SMESHGUI_EXPORT SMESHGUI_CreateDualMeshDlg : public SMESHGUI_Dialog { @@ -49,11 +50,16 @@ public: void ShowWarning(bool); bool isWarningShown(); + QLineEdit* myMeshName; + QCheckBox* myProjShape; + signals: void onClicked( int ); + private: QLabel* myWarning; + QLabel* myMeshNameLabel; }; #endif // SMESHGUI_CREATEDUALMESHDLG_H diff --git a/src/SMESHGUI/SMESHGUI_CreateDualMeshOp.cxx b/src/SMESHGUI/SMESHGUI_CreateDualMeshOp.cxx index 25f811700..449f0a582 100644 --- a/src/SMESHGUI/SMESHGUI_CreateDualMeshOp.cxx +++ b/src/SMESHGUI/SMESHGUI_CreateDualMeshOp.cxx @@ -40,8 +40,12 @@ #include #include #include +#include #include +// Qt includes +#include + // IDL includes #include #include CORBA_SERVER_HEADER(SMESH_MeshEditor) @@ -150,6 +154,9 @@ void SMESHGUI_CreateDualMeshOp::selectionDone() myDlg->ShowWarning( true ); } } + std::string mesh_name = "dual_" + pObj->GetName(); + myDlg->myMeshName->setText(QString(mesh_name.c_str())); + } catch ( const SALOME::SALOME_Exception& S_ex ) { @@ -158,6 +165,7 @@ void SMESHGUI_CreateDualMeshOp::selectionDone() catch ( ... ) { } + } //================================================================================ @@ -217,11 +225,9 @@ bool SMESHGUI_CreateDualMeshOp::onApply() bool aResult = false; SMESH::SMESH_Gen_var gen = SMESHGUI::GetSMESHGen(); SMESH::SMESH_Mesh_var newMesh; - QByteArray newMeshName="MESH_DUAL"; + QByteArray newMeshName=myDlg->myMeshName->text().toUtf8(); try { - // TODO: Call the python script using medcoupling - // String to run medcoupling dual // TODO: change name as previous name + "_dual" newMesh = gen->CreateDualMesh(mesh, newMeshName.constData()); @@ -246,10 +252,11 @@ bool SMESHGUI_CreateDualMeshOp::onApply() if( aResult ) { SMESHGUI::Modified(); - update( UF_ObjBrowser | UF_Model | UF_Viewer ); selectionDone(); - } + update( UF_ObjBrowser | UF_Model | UF_Viewer ); + } + SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); // updateObjBrowser(true); // SMESHGUI::Modified(); diff --git a/src/SMESHGUI/SMESH_images.ts b/src/SMESHGUI/SMESH_images.ts index 2116ee51b..fc90e47de 100644 --- a/src/SMESHGUI/SMESH_images.ts +++ b/src/SMESHGUI/SMESH_images.ts @@ -95,6 +95,10 @@ ICON_CONV_TO_QUAD mesh_conv_to_quad.png + + ICON_CREATE_DUAL_MESH + mesh_create_dual_mesh.png + ICON_CUT mesh_cutGroups.png diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index 7c52712ec..a627143da 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -292,6 +292,10 @@ MEN_COPY_MESH Copy Mesh + + MEN_CREATE_DUAL_MESH + Create Dual Mesh + MEN_CLIP Clipping @@ -3300,6 +3304,10 @@ Use Display Entity menu command to show them. STB_COPY_MESH Copy Mesh + + STB_CREATE_DUAL_MESH + Create Dual Mesh + STB_CLIP Clipping @@ -5679,6 +5687,29 @@ Please specify it and try again Warning: mesh can become non-conformal + + SMESHGUI_CreateDualMeshDlg + + CAPTION + Create Dual Mesh + + + MESH + Mesh or Sub-mesh + + + NON_TETRA_MESH_WARNING + Warning: mesh must have only Tetrahedron 3D elements + + + DUAL_MESH_NAME + Name of the dual mesh + + + PROJ_SHAPE + Project boundary elements on shape + + SMESHGUI_ConvToQuadOp diff --git a/src/SMESH_I/SMESH_Gen_i.cxx b/src/SMESH_I/SMESH_Gen_i.cxx index 79d031823..7157f413c 100644 --- a/src/SMESH_I/SMESH_Gen_i.cxx +++ b/src/SMESH_I/SMESH_Gen_i.cxx @@ -151,6 +151,9 @@ #include #include #include +#include + +namespace fs = boost::filesystem; using namespace std; using SMESH::TPythonDump; @@ -2835,54 +2838,23 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateDualMesh(SMESH::SMESH_IDSource_ptr mesh if ( !srcMesh_i ) THROW_SALOME_CORBA_EXCEPTION( "bad mesh of IDSource", SALOME::BAD_PARAM ); - SMESH_Mesh& srcMesh2 = srcMesh_i->GetImpl(); + CORBA::String_var mesh_var=GetORB()->object_to_string(mesh); + std::string mesh_ior = mesh_var.in(); - // TODO: Get it - CORBA::String_var mesh_ior=GetORB()->object_to_string(mesh); - std::string mesh_id = mesh_ior.in(); - std::string dual_mesh_file="/tmp/test_dual.med"; + fs::path tmp_folder = fs::unique_path(fs::path("dual_mesh-%%%%-%%%%")); + fs::create_directories(tmp_folder); + fs::path dual_mesh_file = tmp_folder / fs::path("tmp_dual_mesh.med"); std::string mesh_name = "MESH"; - std::string python_code; - python_code += "import sys\n"; - python_code += "import salome\n"; - python_code += "import medcoupling as mc\n"; - python_code += "from math import pi\n"; - python_code += "salome.salome_init()\n"; - python_code += "import GEOM\n"; - python_code += "from salome.geom import geomBuilder\n"; - python_code += "geompy = geomBuilder.New()\n"; - python_code += "import SMESH, SALOMEDS\n"; - python_code += "from salome.smesh import smeshBuilder\n"; - python_code += "smesh = smeshBuilder.New()\n"; - python_code += "def create_dual_mesh(mesh_ior, output_file):\n"; - python_code += " mesh = salome.orb.string_to_object(mesh_ior)\n"; - python_code += " shape = mesh.GetShapeToMesh()\n"; - python_code += " if not mesh:\n"; - python_code += " raise Exception(\"Could not find mesh using id: \", mesh_id)\n"; - python_code += " int_ptr = mesh.ExportMEDCoupling(True, True)\n"; - python_code += " dab = mc.FromPyIntPtrToDataArrayByte(int_ptr)\n"; - python_code += " tetras = mc.MEDFileMesh.New(dab)[0]\n"; - python_code += " tetras = mc.MEDCoupling1SGTUMesh(tetras)\n"; - python_code += " polyh = tetras.computeDualMesh()\n"; - python_code += " skin = tetras.buildUnstructured().computeSkin()\n"; - python_code += " skin_polyh = polyh.buildUnstructured().computeSkin()\n"; - python_code += " allNodesOnSkinPolyh = skin_polyh.computeFetchedNodeIds()\n"; - python_code += " allNodesOnSkin = skin.computeFetchedNodeIds()\n"; - python_code += " ptsAdded = allNodesOnSkinPolyh.buildSubstraction(allNodesOnSkin)\n"; - python_code += " ptsAddedMesh = mc.MEDCouplingUMesh.Build0DMeshFromCoords( skin_polyh.getCoords()[ptsAdded] )\n"; - python_code += " ptsAddedCoo = ptsAddedMesh.getCoords()\n"; - python_code += " ptsAddedCooModified = ptsAddedCoo[:]\n"; - python_code += " polyh.setName(\"MESH\")\n"; - python_code += " polyh.write(output_file)\n"; - // Running Python script assert(Py_IsInitialized()); PyGILState_STATE gstate; gstate = PyGILState_Ensure(); - PyRun_SimpleString(python_code.c_str()); - std::string cmd=""; - cmd += "create_dual_mesh(\"" + mesh_id + "\", \"" + dual_mesh_file + "\")"; + + std::string cmd="import salome.smesh.smesh_tools as smt"; + PyRun_SimpleString(cmd.c_str()); + + cmd = "smt.create_dual_mesh(\"" + mesh_ior + "\", \"" + dual_mesh_file.string() + "\", \"" + mesh_name + "\")"; PyRun_SimpleString(cmd.c_str()); PyGILState_Release(gstate); @@ -2896,19 +2868,19 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateDualMesh(SMESH::SMESH_IDSource_ptr mesh if ( !meshSO->_is_nil() ) { SetName( meshSO, meshName, "Mesh" ); - SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED"); + SetPixMap( meshSO, "ICON_SMESH_TREE_MESH"); } SMESH_Mesh& newMesh2 = newMesh_i->GetImpl(); - newMesh2.MEDToMesh(dual_mesh_file.c_str(), "MESH"); + newMesh2.MEDToMesh(dual_mesh_file.c_str(), meshName); SMESHDS_Mesh* newMeshDS = newMesh_i->GetImpl().GetMeshDS(); newMeshDS->Modified(); *pyDump << newMesh << " = " << this - << ".CreateDualMesh( " << mesh << ", " + << ".CreateDualMesh(" << "'" << meshName << "') "; return newMesh._retn(); diff --git a/src/SMESH_SWIG/CMakeLists.txt b/src/SMESH_SWIG/CMakeLists.txt index e39db09f9..81cf38a69 100644 --- a/src/SMESH_SWIG/CMakeLists.txt +++ b/src/SMESH_SWIG/CMakeLists.txt @@ -37,6 +37,7 @@ SET(smesh_SCRIPTS smeshBuilder.py smesh_algorithm.py smesh_selection.py + smesh_tools.py ) SET(StdMeshers_SCRIPTS @@ -52,7 +53,7 @@ SET_SOURCE_FILES_PROPERTIES(SMeshHelper.i PROPERTIES CPLUSPLUS ON) SET_SOURCE_FILES_PROPERTIES(SMeshHelper.i PROPERTIES SWIG_FLAGS "-py3") SET_SOURCE_FILES_PROPERTIES(SMeshHelper_wrap.cpp PROPERTIES COMPILE_FLAGS "-DHAVE_CONFIG_H") SET(_swig_SCRIPTS ${CMAKE_CURRENT_BINARY_DIR}/SMeshHelper.py ) -IF(${CMAKE_VERSION} VERSION_LESS "3.8.0") +IF(${CMAKE_VERSION} VERSION_LESS "3.8.0") SWIG_ADD_MODULE(SMeshHelper python ${SMeshHelper_SOURCES}) ELSE() SWIG_ADD_LIBRARY(SMeshHelper LANGUAGE python SOURCES ${SMeshHelper_SOURCES}) diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index c46a97751..42bad03cf 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -786,11 +786,10 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): Returns: an instance of class :class:`Mesh` """ - if isinstance( mesh, Mesh ): - meshPart = mesh.GetMesh() - mesh = SMESH._objref_SMESH_Gen.CreateDualMesh(self, mesh, meshName) - return Mesh(self, self.geompyD, mesh) + mesh = mesh.GetMesh() + dualMesh = SMESH._objref_SMESH_Gen.CreateDualMesh(self, mesh, meshName) + return Mesh(self, self.geompyD, dualMesh) def CopyMesh( self, meshPart, meshName, toCopyGroups=False, toKeepIDs=False): diff --git a/src/SMESH_SWIG/smesh_tools.py b/src/SMESH_SWIG/smesh_tools.py new file mode 100644 index 000000000..38cd978e0 --- /dev/null +++ b/src/SMESH_SWIG/smesh_tools.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 + +import sys +import salome +import medcoupling as mc +from math import pi + +#salome.salome_init() + +import GEOM +from salome.geom import geomBuilder + +geompy = geomBuilder.New() + +import SMESH, SALOMEDS +from salome.smesh import smeshBuilder + +smesh = smeshBuilder.New() + +def create_dual_mesh(mesh_ior, output_file, adapt_to_shape=True, mesh_name="MESH"): + """ Create a dual of the mesh in input_file into output_file + + Args: + mesh_ior (string): corba Id of the Tetrahedron mesh + output_file (string): dual mesh file + """ + # Import mesh from file + # mesh = salome.orb.string_to_object(salome.salome_study.myStudy.FindObjectID(mesh_id).GetIOR()) + mesh = salome.orb.string_to_object(mesh_ior) + if not mesh: + raise Exception("Could not find mesh using id: ", mesh_ior) + + shape = mesh.GetShapeToMesh() + + # We got a meshProxy so we need to convert pointer to MEDCoupling + int_ptr = mesh.ExportMEDCoupling(True, True) + dab = mc.FromPyIntPtrToDataArrayByte(int_ptr) + tetras = mc.MEDFileMesh.New(dab)[0] + # End of SMESH -> MEDCoupling part for dualmesh + + tetras = mc.MEDCoupling1SGTUMesh(tetras) + polyh = tetras.computeDualMesh() + skin = tetras.buildUnstructured().computeSkin() + skin_polyh = polyh.buildUnstructured().computeSkin() + allNodesOnSkinPolyh = skin_polyh.computeFetchedNodeIds() + allNodesOnSkin = skin.computeFetchedNodeIds() + ptsAdded = allNodesOnSkinPolyh.buildSubstraction(allNodesOnSkin) + ptsAddedMesh = mc.MEDCouplingUMesh.Build0DMeshFromCoords( skin_polyh.getCoords()[ptsAdded] ) + + if adapt_to_shape: + ptsAddedCoo = ptsAddedMesh.getCoords() + ptsAddedCooModified = ptsAddedCoo[:] + + # We need the geometry for that + # TODO : Loop on faces identify points associated to which face + faces = geompy.ExtractShapes(shape, geompy.ShapeType["FACE"], True) + #assert( len(faces) == 1 ) + ## projection des points ajoutés par le dual sur la surface + #for i,tup in enumerate(ptsAddedCooModified): + # vertex = geompy.MakeVertex(*tuple(tup)) + # prj = geompy.MakeProjection(vertex, faces) + # newCoor = geompy.PointCoordinates( prj ) + # ptsAddedCooModified[i] = newCoor + ## assign coordinates with projected ones + #polyh.getCoords()[ptsAdded] = ptsAddedCooModified + + print("Writing dual mesh in ", output_file) + polyh.setName(mesh_name) + polyh.write(output_file) + + + + + diff --git a/test/SMESH_create_dual_mesh.py b/test/SMESH_create_dual_mesh.py new file mode 100644 index 000000000..007dbb8a7 --- /dev/null +++ b/test/SMESH_create_dual_mesh.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +### +### This file is generated automatically by SALOME v9.9.0 with dump python functionality +### + +import sys +import salome + +salome.salome_init() +import salome_notebook +notebook = salome_notebook.NoteBook() +sys.path.insert(0, r'/home/B61570/work_in_progress/dual_mesh') + +### +### GEOM component +### + +import GEOM +from salome.geom import geomBuilder +import math +import SALOMEDS + + +geompy = geomBuilder.New() + +O = geompy.MakeVertex(0, 0, 0) +OX = geompy.MakeVectorDXDYDZ(1, 0, 0) +OY = geompy.MakeVectorDXDYDZ(0, 1, 0) +OZ = geompy.MakeVectorDXDYDZ(0, 0, 1) +Sphere_1 = geompy.MakeSphereR(100) +[geomObj_1] = geompy.ExtractShapes(Sphere_1, geompy.ShapeType["FACE"], True) +geompy.addToStudy( O, 'O' ) +geompy.addToStudy( OX, 'OX' ) +geompy.addToStudy( OY, 'OY' ) +geompy.addToStudy( OZ, 'OZ' ) +geompy.addToStudy( Sphere_1, 'Sphere_1' ) + +### +### SMESH component +### + +import SMESH, SALOMEDS +from salome.smesh import smeshBuilder + +smesh = smeshBuilder.New() + +NETGEN_3D_Parameters_1 = smesh.CreateHypothesisByAverageLength( 'NETGEN_Parameters', 'NETGENEngine', 34.641, 0 ) +Mesh_1 = smesh.Mesh(Sphere_1,'Mesh_1') +status = Mesh_1.AddHypothesis( Sphere_1, NETGEN_3D_Parameters_1 ) +NETGEN_1D_2D_3D = Mesh_1.Tetrahedron(algo=smeshBuilder.NETGEN_1D2D3D) +isDone = Mesh_1.Compute() +dual_Mesh_1 = smesh.CreateDualMesh( Mesh_1, 'dual_Mesh_1') + + +assert(dual_Mesh_1.NbPolyhedrons() > 0) +assert(dual_Mesh_1.NbTetras() == 0) + + +if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser() diff --git a/test/tests.set b/test/tests.set index de38c9f13..f00bde4c6 100644 --- a/test/tests.set +++ b/test/tests.set @@ -62,6 +62,7 @@ SET(BAD_TESTS SMESH_test1.py SMESH_test2.py SMESH_test4.py + SMESH_create_dual_mesh.py ) IF(NOT WIN32) LIST(APPEND BAD_TESTS