Merge branch 'yan/dual_mesh_mc'

This commit is contained in:
Yoann Audouin 2022-10-13 16:22:23 +02:00
commit 33d5b0fd2b
28 changed files with 1202 additions and 126 deletions

View File

@ -0,0 +1,59 @@
# Creating dual Mesh
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
# Creating a sphere
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' )
import SMESH, SALOMEDS
from salome.smesh import smeshBuilder
smesh = smeshBuilder.New()
# Meshing sphere in Tetrahedron
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()
# Creating Dual mesh
dual_Mesh_1 = smesh.CreateDualMesh( Mesh_1, 'dual_Mesh_1', True)
assert(dual_Mesh_1.NbPolyhedrons() > 0)
assert(dual_Mesh_1.NbTetras() == 0)
if salome.sg.hasDesktop():
salome.sg.updateObjBrowser()

View File

@ -128,6 +128,7 @@ SET(BAD_TESTS
transforming_meshes_ex06.py
viewing_meshes_ex01.py
radial_prism_3d_algo.py
create_dual_mesh.py
)
IF(NOT WIN32)
LIST(APPEND BAD_TESTS

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -33,6 +33,8 @@ Mesh module provides several ways to create the mesh:
* A new mesh can be created from a transformed, e.g. :ref:`translated <translation_page>`, part of the mesh.
* A new mesh can be created from the gernation of the :ref:`dual <create_dual_mesh_page>` of a Tetrahedron Mesh.
Meshes can be edited using the MESH functions destined for :ref:`modification <modifying_meshes_page>` of meshes.
@ -82,4 +84,5 @@ Quadratic mesh can be obtained in three ways:
importing_exporting_meshes.rst
building_compounds.rst
copy_mesh.rst
create_dual_mesh.rst
connectivity.rst

View File

@ -0,0 +1,42 @@
.. _create_dual_mesh_page:
****************
Create Dual Mesh
****************
We can create the dual of a Tetrahedron Mesh which will be a polyhedron mesh.
The Mesh is created using MEDCoupling computeDualMesh function.
*To create a dual mesh:*
.. |img| image:: ../images/create_dual_mesh_icon.png
From the contextual menu in the Object Browser of from the **Mesh** menu select
**Create Dual Mesh** or click *"Create Dual Mesh"* button |img| in the toolbar.
The following dialog box will appear:
.. image:: ../images/create_dual_mesh_dlg.png
:align: center
In the dialog:
* specify the mesh for which to create the dual mesh:
* **Select whole mesh** from the study tree. If a mesh was selected before calling function it will be preselected.
* If the mesh is not made of only Tetrahedrons a error message will be displayed and you won't be allowed to go through.
* specify the **New Mesh Name**;
* activate **Project boundary elements on shape** for the boundary points of the
dual mesh to be projected on their associated shape.
* Click **Apply** or **Apply and Close** button to confirm the operation.
----------------------------
Limitations of the dual mesh
----------------------------
Only 2d groups will be transferred to the dual mesh.
If you have convex shape the projection might not improve the mesh.
**See Also** a sample script of :ref:`tui_create_dual_mesh`.

View File

@ -107,3 +107,13 @@ Mesh Copying
:download:`Download this script <../../examples/creating_meshes_ex08.py>`
.. _tui_create_dual_mesh:
Creating Dual Mesh
==================
.. literalinclude:: ../../examples/create_dual_mesh.py
:language: python
:download:`Download this script <../../examples/create_dual_mesh.py>`

View File

@ -284,6 +284,16 @@ module SMESH
in boolean theMakeRequiredGroups,
out SMESH::ComputeError theError)
raises ( SALOME::SALOME_Exception );
/*!
* Create a dual mesh of a Tetrahedron mesh
* \param mesh - TetraHedron mesh to create dual from
* \param meshName - a name of the new mesh
* \param adaptToShape - if True project boundary point on shape
*/
SMESH_Mesh CreateDualMesh(in SMESH_IDSource mesh,
in string meshName,
in boolean adaptToShape)
raises ( SALOME::SALOME_Exception );
/*!
* Create a mesh by copying a part of another mesh

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -157,6 +157,8 @@ SET(_moc_HEADERS
SMESHGUI_AddNodeOnSegmentDlg.h
SMESHGUI_AddNodeOnFaceDlg.h
SMESHGUI_InteractiveOp.h
SMESHGUI_CreateDualMeshDlg.h
SMESHGUI_CreateDualMeshOp.h
)
# header files / no moc processing
@ -283,6 +285,8 @@ SET(_other_SOURCES
SMESHGUI_AddNodeOnSegmentDlg.cxx
SMESHGUI_AddNodeOnFaceDlg.cxx
SMESHGUI_InteractiveOp.cxx
SMESHGUI_CreateDualMeshDlg.cxx
SMESHGUI_CreateDualMeshOp.cxx
)
# sources / to compile

View File

@ -97,6 +97,8 @@
#include "SMESHGUI_SymmetryDlg.h"
#include "SMESHGUI_TranslationDlg.h"
#include "SMESHGUI_TransparencyDlg.h"
#include "SMESHGUI_CreateDualMeshDlg.h"
#include "SMESHGUI_CreateDualMeshOp.h"
#include "SMESHGUI_Utils.h"
#include "SMESHGUI_VTKUtils.h"
@ -3051,6 +3053,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
// Adaptation - end
case SMESHOp::OpSplitBiQuadratic:
case SMESHOp::OpConvertMeshToQuadratic:
case SMESHOp::OpCreateDualMesh:
case SMESHOp::OpCreateBoundaryElements: // create 2D mesh from 3D
case SMESHOp::OpReorientFaces:
case SMESHOp::OpCreateGeometryGroup:
@ -4275,6 +4278,7 @@ void SMESHGUI::initialize( CAM_Application* app )
createSMESHAction( SMESHOp::OpRevolution, "REVOLUTION", "ICON_REVOLUTION" );
createSMESHAction( SMESHOp::OpPatternMapping, "MAP", "ICON_MAP" );
createSMESHAction( SMESHOp::OpConvertMeshToQuadratic, "CONV_TO_QUAD", "ICON_CONV_TO_QUAD" );
createSMESHAction( SMESHOp::OpCreateDualMesh, "CREATE_DUAL_MESH","ICON_CREATE_DUAL_MESH" );
createSMESHAction( SMESHOp::OpCreateBoundaryElements, "2D_FROM_3D", "ICON_2D_FROM_3D" );
createSMESHAction( SMESHOp::OpReset, "RESET" );
@ -4411,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 );
@ -6025,6 +6030,9 @@ LightApp_Operation* SMESHGUI::createOperation( const int id ) const
case SMESHOp::OpCreateBoundaryElements: // create 2D mesh as boundary on 3D
op = new SMESHGUI_Make2DFrom3DOp();
break;
case SMESHOp::OpCreateDualMesh:
op = new SMESHGUI_CreateDualMeshOp();
break;
case SMESHOp::OpReorientFaces:
op = new SMESHGUI_ReorientFacesOp();
break;

View File

@ -0,0 +1,96 @@
// Copyright (C) 2007-2021 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, or (at your option) any later version.
//
// 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_CreateDualMeshDlg.cxx
// Author : Yoann AUDOUIN (EDF)
// SMESH includes
//
#include "SMESHGUI_CreateDualMeshDlg.h"
#include "SMESHGUI_CreateDualMeshOp.h"
// Qt includes
#include <QGroupBox>
#include <QCheckBox>
#include <QRadioButton>
#include <QButtonGroup>
#include <QGroupBox>
#include <QFrame>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#define SPACING 6
#define MARGIN 11
SMESHGUI_CreateDualMeshDlg::SMESHGUI_CreateDualMeshDlg()
: SMESHGUI_Dialog( 0, false, true )
{
setWindowTitle( tr( "CAPTION" ) );
// Create top controls
// mesh
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("<b>%1</b>").arg(tr("NON_TETRA_MESH_WARNING")), mainFrame());
// Fill layout
QGridLayout* aLay = new QGridLayout( mainFrame() );
aLay->setMargin( 5 );
aLay->setSpacing( 5 );
aLay->addWidget( objectWg( 0, Label ), 0, 0 );
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 );
}
SMESHGUI_CreateDualMeshDlg::~SMESHGUI_CreateDualMeshDlg()
{
}
void SMESHGUI_CreateDualMeshDlg::ShowWarning(bool toShow)
{
if ( toShow )
myWarning->show();
else
myWarning->hide();
}
bool SMESHGUI_CreateDualMeshDlg::isWarningShown()
{
return myWarning->isVisible();
}

View File

@ -0,0 +1,65 @@
// Copyright (C) 2007-2021 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, or (at your option) any later version.
//
// 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_CreateDualMeshDlg.h
// Author : Yoann Audouin (EDF)
//
#ifndef SMESHGUI_CREATEDUALMESHDLG_H
#define SMESHGUI_CREATEDUALMESHDLG_H
// SMESH includes
#include "SMESH_SMESHGUI.hxx"
#include "SMESHGUI_Dialog.h"
class QCheckBox;
class QRadioButton;
class QButtonGroup;
class QGroupBox;
class QLabel;
class QLineEdit;
class SMESHGUI_EXPORT SMESHGUI_CreateDualMeshDlg : public SMESHGUI_Dialog
{
Q_OBJECT
public:
SMESHGUI_CreateDualMeshDlg();
virtual ~SMESHGUI_CreateDualMeshDlg();
void ShowWarning(bool);
bool isWarningShown();
QLineEdit* myMeshName;
QCheckBox* myProjShape;
signals:
void onClicked( int );
private:
QLabel* myWarning;
QLabel* myMeshNameLabel;
};
#endif // SMESHGUI_CREATEDUALMESHDLG_H

View File

@ -0,0 +1,293 @@
// Copyright (C) 2007-2021 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, or (at your option) any later version.
//
// 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_CreateDualMeshOp.cxx
// Author : Yoann AUDOUIN (EDF)
// SMESH includes
//
#include "SMESHGUI_CreateDualMeshOp.h"
#include "SMESHGUI.h"
#include "SMESHGUI_CreateDualMeshDlg.h"
#include "SMESHGUI_MeshEditPreview.h"
#include "SMESHGUI_Utils.h"
#include "SMESH_ActorUtils.h"
#include "SMESH_TypeFilter.hxx"
#include "SMDSAbs_ElementType.hxx"
// SALOME GUI includes
#include <LightApp_UpdateFlags.h>
#include <SUIT_MessageBox.h>
#include <SUIT_OverrideCursor.h>
#include <SalomeApp_Tools.h>
#include <SalomeApp_Application.h>
#include <SALOME_Actor.h>
// Qt includes
#include <QLineEdit>
#include <QCheckBox>
// IDL includes
#include <SALOMEconfig.h>
#include CORBA_SERVER_HEADER(SMESH_MeshEditor)
// VTK includes
#include <vtkProperty.h>
//================================================================================
/*!
* \brief Constructor
*
* Initialize operation
*/
//================================================================================
SMESHGUI_CreateDualMeshOp::SMESHGUI_CreateDualMeshOp()
: SMESHGUI_SelectionOp(),
myDlg( 0 )
{
}
//================================================================================
/*!
* \brief Destructor
*/
//================================================================================
SMESHGUI_CreateDualMeshOp::~SMESHGUI_CreateDualMeshOp()
{
if ( myDlg ) delete myDlg;
}
//================================================================================
/*!
* \brief Gets dialog of this operation
* \retval LightApp_Dialog* - pointer to dialog of this operation
*/
//================================================================================
LightApp_Dialog* SMESHGUI_CreateDualMeshOp::dlg() const
{
return myDlg;
}
//================================================================================
/*!
* \brief Creates dialog if necessary and shows it
*
* Virtual method redefined from base class called when operation is started creates
* dialog if necessary and shows it, activates selection
*/
//================================================================================
void SMESHGUI_CreateDualMeshOp::startOperation()
{
if( !myDlg )
{
myDlg = new SMESHGUI_CreateDualMeshDlg( );
}
connect( myDlg, SIGNAL( onClicked( int ) ), SLOT( ConnectRadioButtons( int ) ) );
myHelpFileName = "create_dual_mesh.html";
SMESHGUI_SelectionOp::startOperation();
myDlg->activateObject( 0 );
myDlg->ShowWarning( false );
myDlg->show();
selectionDone();
}
//================================================================================
/*!
* \brief Updates dialog's look and feel
*
* Virtual method redefined from the base class updates dialog's look and feel
*/
//================================================================================
void SMESHGUI_CreateDualMeshOp::selectionDone()
{
if ( !dlg()->isVisible() )
return;
SMESHGUI_SelectionOp::selectionDone();
try
{
QString anObjEntry = myDlg->selectedObject( 0 );
_PTR(SObject) pObj = SMESH::getStudy()->FindObjectID( anObjEntry.toUtf8().data() );
if ( !pObj ) return;
SMESH::SMESH_IDSource_var idSource =
SMESH::SObjectToInterface<SMESH::SMESH_IDSource>( pObj );
myDlg->setButtonEnabled( true, QtxDialog::OK | QtxDialog::Apply );
if( idSource->_is_nil() )
{
myDlg->setButtonEnabled( false, QtxDialog::OK | QtxDialog::Apply );
return;
}
SMESH::SMESH_Mesh_var mesh = idSource->GetMesh();
// show warning on non-conformal result mesh
if ( ! idSource->_is_nil() )
{
SMESH::SMESH_subMesh_var subMesh =
SMESH::SObjectToInterface<SMESH::SMESH_subMesh>( pObj );
// Check that mesh is only tetra
if (!checkMesh(idSource)){
myDlg->ShowWarning( true );
myDlg->setButtonEnabled(false, QtxDialog::OK|QtxDialog::Apply);
}
}
std::string mesh_name = "dual_" + pObj->GetName();
myDlg->myMeshName->setText(QString(mesh_name.c_str()));
}
catch ( const SALOME::SALOME_Exception& S_ex )
{
SalomeApp_Tools::QtCatchCorbaException( S_ex );
}
catch ( ... )
{
}
}
//================================================================================
/*!
* \brief Creates selection filter
* \param theId - identifier of current selection widget
* \retval SUIT_SelectionFilter* - pointer to the created filter or null
*
* Creates selection filter in accordance with identifier of current selection widget
*/
//================================================================================
SUIT_SelectionFilter* SMESHGUI_CreateDualMeshOp::createFilter( const int theId ) const
{
if ( theId == 0 )
return new SMESH_TypeFilter( SMESH::MESHorSUBMESH );
else
return 0;
}
//================================================================================
/*!
* \brief Edits mesh
*
* Virtual slot redefined from the base class called when "Apply" button is clicked
*/
//================================================================================
bool SMESHGUI_CreateDualMeshOp::onApply()
{
SUIT_OverrideCursor aWaitCursor;
QString aMess;
QStringList anEntryList;
QString anObjEntry = myDlg->selectedObject( 0 );
_PTR(SObject) pObj = SMESH::getStudy()->FindObjectID( anObjEntry.toUtf8().data() );
if ( !pObj )
{
dlg()->show();
SUIT_MessageBox::warning( myDlg,
tr( "SMESH_WRN_WARNING" ), tr("MESH_IS_NOT_SELECTED") );
return false;
}
SMESH::SMESH_Mesh_var mesh;
SMESH::SMESH_IDSource_var idSource =
SMESH::SObjectToInterface<SMESH::SMESH_IDSource>( pObj );
if( !CORBA::is_nil(idSource) )
mesh = idSource->GetMesh();
if( CORBA::is_nil(mesh) )
{
SUIT_MessageBox::warning( myDlg,
tr( "SMESH_WRN_WARNING" ), tr("REF_IS_NULL") );
return false;
}
bool aResult = false;
SMESH::SMESH_Gen_var gen = SMESHGUI::GetSMESHGen();
SMESH::SMESH_Mesh_var newMesh;
QByteArray newMeshName=myDlg->myMeshName->text().toUtf8();
bool adapt_to_shape=myDlg->myProjShape->isChecked();
try
{
newMesh = gen->CreateDualMesh(mesh, newMeshName.constData(), adapt_to_shape);
if ( !newMesh->_is_nil() )
if ( _PTR(SObject) aSObject = SMESH::ObjectToSObject( newMesh ) )
{
anEntryList.append( aSObject->GetID().c_str() );
SMESH::SetName( aSObject, newMeshName );
}
aResult = true;
}
catch ( const SALOME::SALOME_Exception& S_ex )
{
SalomeApp_Tools::QtCatchCorbaException( S_ex );
aResult = false;
}
catch ( ... )
{
aResult = false;
}
if( aResult )
{
SMESHGUI::Modified();
selectionDone();
update( UF_ObjBrowser | UF_Model | UF_Viewer );
}
SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser();
// updateObjBrowser(true);
// SMESHGUI::Modified();
// if( LightApp_Application* anApp =
// dynamic_cast<LightApp_Application*>( SUIT_Session::session()->activeApplication() ) )
// anApp->browseObjects( anEntryList, true );
return true;
}
//================================================================================
/*! checkMesh
* Verify that mesh as only tetraheadrons as 3D elements
*/
//================================================================================
bool
SMESHGUI_CreateDualMeshOp::checkMesh( const SMESH::SMESH_IDSource_var& idSource)
{
SMESH::smIdType_array_var nbElemOfType = idSource->GetMeshInfo();
// Checking that the mesh only has Tetrahedron
bool hasOnlyTetra = (
nbElemOfType[SMDSEntity_Tetra ] &&
!nbElemOfType[SMDSEntity_Hexa ] &&
!nbElemOfType[SMDSEntity_Pyramid ] &&
!nbElemOfType[SMDSEntity_Polygon ] &&
!nbElemOfType[SMDSEntity_Penta ] );
return hasOnlyTetra;
}

View File

@ -0,0 +1,64 @@
// Copyright (C) 2007-2021 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, or (at your option) any later version.
//
// 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_CreateDualMeshOp.h
// Author : Yoann AUDOUIN (EDF)
//
#ifndef SMESHGUI_CREATEDUALMESHOP_H
#define SMESHGUI_CREATEDUALMESHOP_H
// SMESH includes
#include "SMESH_SMESHGUI.hxx"
#include "SMESHGUI_SelectionOp.h"
// IDL includes
#include <SALOMEconfig.h>
#include CORBA_SERVER_HEADER(SMESH_Mesh)
class SMESHGUI_CreateDualMeshDlg;
class SMESHGUI_EXPORT SMESHGUI_CreateDualMeshOp : public SMESHGUI_SelectionOp
{
Q_OBJECT
public:
SMESHGUI_CreateDualMeshOp();
virtual ~SMESHGUI_CreateDualMeshOp();
virtual LightApp_Dialog* dlg() const;
static bool checkMesh( const SMESH::SMESH_IDSource_var& );
protected:
virtual void startOperation();
virtual void selectionDone();
virtual SUIT_SelectionFilter* createFilter( const int ) const;
protected slots:
virtual bool onApply();
private:
SMESHGUI_CreateDualMeshDlg* myDlg;
};
#endif // SMESHGUI_CREATEDUALMESHOP_H

View File

@ -186,6 +186,7 @@ namespace SMESHOp {
OpMoveNodeInteractive = 4516, // MENU MODIFICATION - MOVE NODE INTERACTIVE
OpSplitEdgeInteract = 4517, // MENU MODIFICATION - INTERACTIVE ADD NODE ON EDGE
OpSplitFaceInteract = 4518, // MENU MODIFICATION - INTERACTIVE ADD NODE ON FACE
OpCreateDualMesh = 4519, // MENU MODIFICATION - CREATE DUAL MESH
// Adaptation ---------------------//--------------------------------
OpMGAdapt = 8020, // MENU ADAPTATION - MG-ADAPT
OpHomardAdapt = 8021, // MENU ADAPTATION - HOMARD-ADAPT

View File

@ -95,6 +95,10 @@
<source>ICON_CONV_TO_QUAD</source>
<translation>mesh_conv_to_quad.png</translation>
</message>
<message>
<source>ICON_CREATE_DUAL_MESH</source>
<translation>mesh_create_dual_mesh.png</translation>
</message>
<message>
<source>ICON_CUT</source>
<translation>mesh_cutGroups.png</translation>

View File

@ -292,6 +292,10 @@
<source>MEN_COPY_MESH</source>
<translation>Copy Mesh</translation>
</message>
<message>
<source>MEN_CREATE_DUAL_MESH</source>
<translation>Create Dual Mesh</translation>
</message>
<message>
<source>MEN_CLIP</source>
<translation>Clipping</translation>
@ -3300,6 +3304,10 @@ Use Display Entity menu command to show them.
<source>STB_COPY_MESH</source>
<translation>Copy Mesh</translation>
</message>
<message>
<source>STB_CREATE_DUAL_MESH</source>
<translation>Create Dual Mesh</translation>
</message>
<message>
<source>STB_CLIP</source>
<translation>Clipping</translation>
@ -5679,6 +5687,29 @@ Please specify it and try again</translation>
<translation>Warning: mesh can become non-conformal</translation>
</message>
</context>
<context>
<name>SMESHGUI_CreateDualMeshDlg</name>
<message>
<source>CAPTION</source>
<translation>Create Dual Mesh</translation>
</message>
<message>
<source>MESH</source>
<translation>Mesh or Sub-mesh</translation>
</message>
<message>
<source>NON_TETRA_MESH_WARNING</source>
<translation>Warning: mesh must have only Tetrahedron 3D elements</translation>
</message>
<message>
<source>DUAL_MESH_NAME</source>
<translation>Name of the dual mesh</translation>
</message>
<message>
<source>PROJ_SHAPE</source>
<translation>Project boundary elements on shape</translation>
</message>
</context>
<context>
<name>SMESHGUI_ConvToQuadOp</name>
<message>

View File

@ -1022,6 +1022,7 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
}
if ( method == "CreateMeshesFromUNV" ||
method == "CreateMeshesFromSTL" ||
method == "CreateDualMesh" ||
method == "CopyMesh" ) // command result is a mesh
{
Handle(_pyMesh) mesh = new _pyMesh( theCommand, theCommand->GetResultValue() );

View File

@ -49,6 +49,10 @@
#include <TopoDS_Wire.hxx>
#include <gp_Pnt.hxx>
// Have to be included before std headers
#include <Python.h>
#include <structmember.h>
#ifdef WIN32
#include <windows.h>
#include <process.h>
@ -147,6 +151,9 @@
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/string.hpp>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
using namespace std;
using SMESH::TPythonDump;
@ -2802,6 +2809,133 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::ListOfIDSources& theMeshesArray,
return newMesh._retn();
}
//================================================================================
/*!
* \brief Create a mesh by copying a part of another mesh
* \param mesh - TetraHedron mesh
* \param meshName Name of the created mesh
* \retval SMESH::SMESH_Mesh_ptr - the new mesh
*/
//================================================================================
SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateDualMesh(SMESH::SMESH_IDSource_ptr mesh,
const char* meshName,
CORBA::Boolean adapt_to_shape)
{
Unexpect aCatch(SALOME_SalomeException);
TPythonDump* pyDump = new TPythonDump(this); // prevent dump from CreateMesh()
std::unique_ptr<TPythonDump> pyDumpDeleter( pyDump );
// 1. Get source mesh
if ( CORBA::is_nil( mesh ))
THROW_SALOME_CORBA_EXCEPTION( "bad IDSource", SALOME::BAD_PARAM );
SMESH::SMESH_Mesh_var srcMesh = mesh->GetMesh();
SMESH_Mesh_i* srcMesh_i = SMESH::DownCast<SMESH_Mesh_i*>( srcMesh );
if ( !srcMesh_i )
THROW_SALOME_CORBA_EXCEPTION( "bad mesh of IDSource", SALOME::BAD_PARAM );
CORBA::String_var mesh_var=GetORB()->object_to_string(mesh);
std::string mesh_ior = mesh_var.in();
//temporary folder for the generation of the med file
fs::path tmp_folder = fs::temp_directory_path() / 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(meshName);
MESSAGE("Working in folder" + tmp_folder.string());
// Running Python script
assert(Py_IsInitialized());
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
std::string ats;
if(adapt_to_shape)
ats = "True";
else
ats = "False";
std::string cmd="import salome.smesh.smesh_tools as smt\n";
cmd +="smt.smesh_create_dual_mesh(\"" + mesh_ior + "\", \"" +
dual_mesh_file.string() + "\", mesh_name=\"" + mesh_name + "\", adapt_to_shape=" + ats + ")";
MESSAGE(cmd);
PyObject *py_main = PyImport_AddModule("__main__");
PyObject *py_dict = PyModule_GetDict(py_main);
PyRun_String(cmd.c_str(), Py_file_input, py_dict, py_dict);
if (PyErr_Occurred()) {
// Restrieving python error
MESSAGE("Catching error")
PyObject *errtype, *errvalue, *traceback;
PyErr_Fetch(&errtype, &errvalue, &traceback);
if(errvalue != NULL) {
MESSAGE("Error has a value")
PyObject *s = PyObject_Str(errvalue);
Py_ssize_t size;
std::string msg = PyUnicode_AsUTF8AndSize(s, &size);
msg = "Issue with the execution of create_dual_mesh:\n"+msg;
MESSAGE("throwing exception")
// We need to deactivate the GIL before throwing the exception
PyGILState_Release(gstate);
THROW_SALOME_CORBA_EXCEPTION(msg.c_str(), SALOME::INTERNAL_ERROR );
Py_DECREF(s);
}
Py_XDECREF(errvalue);
Py_XDECREF(errtype);
Py_XDECREF(traceback);
}
PyGILState_Release(gstate);
MESSAGE("Mesh created in " + dual_mesh_file.string());
// Import created MED
SMESH::SMESH_Mesh_var newMesh = CreateMesh(GEOM::GEOM_Object::_nil());
SMESH_Mesh_i* newMesh_i = SMESH::DownCast<SMESH_Mesh_i*>( newMesh );
if ( !newMesh_i )
THROW_SALOME_CORBA_EXCEPTION( "can't create a mesh", SALOME::INTERNAL_ERROR );
SALOMEDS::SObject_wrap meshSO = ObjectToSObject( newMesh );
if ( !meshSO->_is_nil() )
{
SetName( meshSO, meshName, meshName );
SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
}
int ret = newMesh_i->ImportMEDFile(dual_mesh_file.c_str(), meshName);
if(ret)
THROW_SALOME_CORBA_EXCEPTION( "Issue when importing mesh", SALOME::INTERNAL_ERROR );
/*
SMESH_Mesh& newMesh2 = newMesh_i->GetImpl();
MESSAGE("Loading file: " << dual_mesh_file.string() << " with mesh " << meshName);
int ret = newMesh2.MEDToMesh(dual_mesh_file.c_str(), meshName);
*/
newMesh_i->GetImpl().GetMeshDS()->Modified();
*pyDump << newMesh << " = " << this
<< ".CreateDualMesh("
<< mesh << ", "
<< "'" << mesh_name << "', "
<< ats << ") ";
pyDumpDeleter.reset(); // allow dump in GetGroups()
if ( srcMesh_i->GetImpl().GetGroupIds().size() > 0 ) // dump created groups
MESSAGE("Dump of groups");
SMESH::ListOfGroups_var groups = newMesh->GetGroups();
return newMesh._retn();
}
//================================================================================
/*!
* \brief Create a mesh by copying a part of another mesh

View File

@ -253,6 +253,11 @@ public:
CORBA::Boolean theMakeRequiredGroups,
SMESH::ComputeError_out theError);
// Create dual mesh of a tetrahedron mesh
SMESH::SMESH_Mesh_ptr CreateDualMesh(SMESH::SMESH_IDSource_ptr meshPart,
const char* meshName,
CORBA::Boolean adapt_to_shape);
// Copy a part of mesh
SMESH::SMESH_Mesh_ptr CopyMesh(SMESH::SMESH_IDSource_ptr meshPart,
const char* meshName,

View File

@ -37,6 +37,7 @@ SET(smesh_SCRIPTS
smeshBuilder.py
smesh_algorithm.py
smesh_selection.py
smesh_tools.py
)
SET(StdMeshers_SCRIPTS

View File

@ -773,6 +773,27 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
aMesh = Mesh( self, self.geompyD, aSmeshMesh, name=name )
return aMesh
def CreateDualMesh( self, mesh, meshName, adaptToShape):
"""
Create a dual of a mesh.
Parameters:
mesh: Tetrahedron mesh
:class:`mesh, <SMESH.SMESH_IDSource>`.
meshName: a name of the new mesh
adpatToShape: if true project boundary points on shape
Returns:
an instance of class :class:`Mesh`
"""
if isinstance( mesh, Mesh ):
mesh = mesh.GetMesh()
print("calling createdualmesh from Python")
dualMesh = SMESH._objref_SMESH_Gen.CreateDualMesh(self, mesh, meshName, adaptToShape)
return Mesh(self, self.geompyD, dualMesh)
def CopyMesh( self, meshPart, meshName, toCopyGroups=False, toKeepIDs=False):
"""
Create a mesh by copying a part of another mesh.

View File

@ -0,0 +1,127 @@
#!/usr/bin/env python3
import sys
import salome
import medcoupling as mc
from math import pi
import numpy as np
#salome.salome_init()
import GEOM
from salome.geom import geomBuilder
geompy = geomBuilder.New()
import SMESH, SALOMEDS
from salome.smesh import smeshBuilder
smesh = smeshBuilder.New()
from salome.kernel.logger import Logger
logger = Logger("salome.smesh.smesh_tools")
logger.setLevel("DEBUG")
def smesh_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(mesh_ior)
if not mesh:
raise Exception("Could not find mesh using id: ", mesh_ior)
shape = mesh.GetShapeToMesh()
# Creating output file
logger.debug("Creating file with mesh: "+mesh_name)
myfile = mc.MEDFileUMesh()
myfile.setName(mesh_name)
# We got a meshProxy so we need to convert pointer to MEDCoupling
int_ptr = mesh.ExportMEDCoupling(True, True)
dab = mc.FromPyIntPtrToDataArrayByte(int_ptr)
mc_mesh_file = mc.MEDFileMesh.New(dab)
tetras = mc_mesh_file[0]
# End of SMESH -> MEDCoupling part for dualmesh
tetras = mc.MEDCoupling1SGTUMesh(tetras)
polyh = tetras.computeDualMesh()
## Adding skin + transfering groups on faces from tetras mesh
mesh2d = polyh.buildUnstructured().computeSkin()
mesh2d.setName(mesh_name)
myfile.setMeshAtLevel(-1, mesh2d)
for grp_name in mc_mesh_file.getGroupsOnSpecifiedLev(-1):
# This group is created by the export
if grp_name == "Group_Of_All_Faces":
logger.debug("Skipping group: "+ grp_name)
continue
logger.debug("Transferring group: "+ grp_name)
grp_tria = mc_mesh_file.getGroup(-1, grp_name)
# Retrieve the nodes in group
grp_nodes = grp_tria.computeFetchedNodeIds()
# Find all the cells lying on one of the nodes
id_grp_poly = mesh2d.getCellIdsLyingOnNodes(grp_nodes, False)
grp_poly = mesh2d[id_grp_poly]
# We use the interpolation to remove the element that are not really in
# the group (the ones that are next to a nodes nut not in the group
# will have the sum of their column in the enterpolation matrix equal
# to zero)
rem = mc.MEDCouplingRemapper()
rem.prepare(grp_poly, grp_tria, "P0P0")
m = rem.getCrudeCSRMatrix()
_, id_to_keep = np.where(m.sum(dtype=np.int64, axis=0) >= 1e-07)
id_grp_poly = id_grp_poly[id_to_keep.tolist()]
id_grp_poly.setName(grp_name)
myfile.addGroup(-1, id_grp_poly)
# Getting list of new points added on the skin
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:
logger.debug("Adapting to shape")
ptsAddedCoo = ptsAddedMesh.getCoords()
ptsAddedCooModified = ptsAddedCoo[:]
# Matching faces with their ids
faces = geompy.ExtractShapes(shape, geompy.ShapeType["FACE"], True)
id2face = {}
for face in faces:
id2face[face.GetSubShapeIndices()[0]] = face
## Projecting each points added by the dual mesh on the surface it is
# associated with
for i, tup in enumerate(ptsAddedCooModified):
vertex = geompy.MakeVertex(*tuple(tup))
shapes = geompy.GetShapesNearPoint(shape, vertex,
geompy.ShapeType["FACE"])
prj = geompy.MakeProjection(vertex,
id2face[shapes.GetSubShapeIndices()[0]])
new_coor = geompy.PointCoordinates(prj)
ptsAddedCooModified[i] = new_coor
polyh.getCoords()[ptsAdded] = ptsAddedCooModified
polyh.setName(mesh_name)
myfile.setMeshAtLevel(0, polyh)
logger.debug("Writting dual mesh in :"+output_file)
myfile.write(output_file, 2)

View File

@ -0,0 +1,94 @@
#!/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)
Cylinder_1 = geompy.MakeCylinderRH(100, 400)
Sphere_1 = geompy.MakeSpherePntR(O, 100)
Fuse_1 = geompy.MakeFuseList([Cylinder_1, Sphere_1], True, True)
[geomObj_1,geomObj_2,geomObj_3] = geompy.ExtractShapes(Fuse_1, geompy.ShapeType["FACE"], True)
top = geompy.CreateGroup(Fuse_1, geompy.ShapeType["FACE"])
geompy.UnionIDs(top, geomObj_1.GetSubShapeIndices())
middle = geompy.CreateGroup(Fuse_1, geompy.ShapeType["FACE"])
geompy.UnionIDs(middle, geomObj_2.GetSubShapeIndices())
bottom = geompy.CreateGroup(Fuse_1, geompy.ShapeType["FACE"])
geompy.UnionIDs(bottom, geomObj_3.GetSubShapeIndices())
#[top, middle, bottom] = geompy.GetExistingSubObjects(Fuse_1, False)
geompy.addToStudy( O, 'O' )
geompy.addToStudy( OX, 'OX' )
geompy.addToStudy( OY, 'OY' )
geompy.addToStudy( OZ, 'OZ' )
geompy.addToStudy( Cylinder_1, 'Cylinder_1' )
geompy.addToStudy( Sphere_1, 'Sphere_1' )
geompy.addToStudy( Fuse_1, 'Fuse_1' )
geompy.addToStudyInFather( Fuse_1, top, 'top' )
geompy.addToStudyInFather( Fuse_1, middle, 'middle' )
geompy.addToStudyInFather( Fuse_1, bottom, 'bottom' )
###
### SMESH component
###
import SMESH, SALOMEDS
from salome.smesh import smeshBuilder
smesh = smeshBuilder.New()
NETGEN_3D_Parameters_1 = smesh.CreateHypothesisByAverageLength( 'NETGEN_Parameters', 'NETGENEngine', 50, 0 )
Mesh_1 = smesh.Mesh(Fuse_1,'Mesh_1')
status = Mesh_1.AddHypothesis( Fuse_1, NETGEN_3D_Parameters_1 )
NETGEN_1D_2D_3D = Mesh_1.Tetrahedron(algo=smeshBuilder.NETGEN_1D2D3D)
top_1 = Mesh_1.GroupOnGeom(top,'top',SMESH.FACE)
middle_1 = Mesh_1.GroupOnGeom(middle,'middle',SMESH.FACE)
bottom_1 = Mesh_1.GroupOnGeom(bottom,'bottom',SMESH.FACE)
isDone = Mesh_1.Compute()
[ top_1, middle_1, bottom_1 ] = Mesh_1.GetGroups()
dual_Mesh_raw_1 = smesh.CreateDualMesh(Mesh_1, 'dual_Mesh_raw_1', False)
dual_Mesh_1 = smesh.CreateDualMesh(Mesh_1, 'dual_Mesh_1', True)
[ top_2, middle_2, bottom_2 ] = dual_Mesh_1.GetGroups()
#Comparing volumes
dual_volume = dual_Mesh_1.GetVolume()
dual_raw_volume = dual_Mesh_raw_1.GetVolume()
print("dual_volume: ", dual_volume)
print("dual_raw_volume: ", dual_raw_volume)
assert (dual_volume >= dual_raw_volume)
if salome.sg.hasDesktop():
salome.sg.updateObjBrowser()

View File

@ -62,6 +62,7 @@ SET(BAD_TESTS
SMESH_test1.py
SMESH_test2.py
SMESH_test4.py
SMESH_create_dual_mesh_adapt.py
)
IF(NOT WIN32)
LIST(APPEND BAD_TESTS