diff --git a/doc/salome/examples/transforming_meshes_ex13.py b/doc/salome/examples/transforming_meshes_ex13.py index fb56273ba..37a3f5eed 100644 --- a/doc/salome/examples/transforming_meshes_ex13.py +++ b/doc/salome/examples/transforming_meshes_ex13.py @@ -1,4 +1,4 @@ -# Reorient faces by vector +# Reorient faces import salome @@ -52,3 +52,20 @@ mesh.Reorient2D( group, smesh.MakeDirStruct( -10, 1, 10 ), [0,0,0]) # # FaceOrPoint - a SMESH.PointStruct structure mesh.Reorient2D( localAlgo.GetSubMesh().GetIDs(), [10,1,0], SMESH.PointStruct(0,0,0)) + + +# Use Reorient2DBy3D() to orient faces of 2 geom faces to have their normal pointing inside volumes + +mesh3D = smesh.Mesh( box, '3D mesh') +mesh3D.AutomaticHexahedralization(0.5) +group0 = mesh3D.Group( faces[0] ) +group1 = mesh3D.Group( faces[1] ) + +# pass group0 and ids of faces of group1 to inverse +nbRev = mesh3D.Reorient2DBy3D([ group0, group1.GetIDs() ], mesh3D, theOutsideNormal=False) +print "Nb reoriented faces:", nbRev + +# orient the reversed faces back +nbRev = mesh3D.Reorient2DBy3D( mesh3D, mesh3D, theOutsideNormal=True) +print "Nb re-reoriented faces:", nbRev + diff --git a/doc/salome/gui/SMESH/images/reorient_2d_face.png b/doc/salome/gui/SMESH/images/reorient_2d_face.png index b143ac4eb..0407fafed 100644 Binary files a/doc/salome/gui/SMESH/images/reorient_2d_face.png and b/doc/salome/gui/SMESH/images/reorient_2d_face.png differ diff --git a/doc/salome/gui/SMESH/images/reorient_2d_point.png b/doc/salome/gui/SMESH/images/reorient_2d_point.png index 844ac09ef..8440c9137 100644 Binary files a/doc/salome/gui/SMESH/images/reorient_2d_point.png and b/doc/salome/gui/SMESH/images/reorient_2d_point.png differ diff --git a/doc/salome/gui/SMESH/images/reorient_2d_volume.png b/doc/salome/gui/SMESH/images/reorient_2d_volume.png new file mode 100644 index 000000000..1d04de0d1 Binary files /dev/null and b/doc/salome/gui/SMESH/images/reorient_2d_volume.png differ diff --git a/doc/salome/gui/SMESH/input/reorient_faces.doc b/doc/salome/gui/SMESH/input/reorient_faces.doc index db408ef08..519da7ef1 100644 --- a/doc/salome/gui/SMESH/input/reorient_faces.doc +++ b/doc/salome/gui/SMESH/input/reorient_faces.doc @@ -1,49 +1,66 @@ /*! -\page reorient_faces_page Reorient faces by vector +\page reorient_faces_page Reorient faces -\n This operation allows changing orientation of a set of neighboring -faces. The desired orientation is defined by a vector. Since the direction -of face normals in the set can be even opposite, it is necessary to -specify a control face whose normal will be compared with the vector. This -face can be either specified explicitly or found by proximity to -a given point. +\n This operation allows changing orientation of faces two ways. +
    +
  1. To reorient a set of neighboring faces by defining the desired + orientation by a vector.
    Since the direction of face normals in + the set can be even opposite, it is necessary to specify a control + face whose normal will be compared with the vector. This face can be + either
  2. +
  3. To reorient faces with relation to adjacent volumes.
  4. +
Orientation of a face is changed by reverting the order of its nodes. To change orientation of faces:
    -
  1. In the \b Modification menu select Reorient faces by - vector item or click Reorient faces by - vector button in the toolbar. +
  2. In the \b Modification menu select Reorient faces + item or click Reorient faces button in the toolbar.
    \image html reorient_faces_face.png -"Reorient faces by vector" button +"Reorient faces" button
    The following dialog box will appear:
    -\image html reorient_2d_point.png -\image html reorient_2d_face.png +\image html reorient_2d_point.png "First mode: to reorient adjacent faces according to a vector. The control face is found by point." +
    +\image html reorient_2d_face.png "Second mode: to reorient adjacent faces according to a vector. The control face is explicitly given." +
    +\image html reorient_2d_volume.png "Third mode: to reorient faces with relation to adjacent volumes."
  3. In this dialog
  4. @@ -51,6 +68,6 @@ The following dialog box will appear:

See Also a sample TUI Script of a -\ref tui_reorient_faces "Reorient faces by vector" operation. +\ref tui_reorient_faces "Reorient faces" operation. */ diff --git a/idl/SMESH_MeshEditor.idl b/idl/SMESH_MeshEditor.idl index 397efff44..293c8c8de 100644 --- a/idl/SMESH_MeshEditor.idl +++ b/idl/SMESH_MeshEditor.idl @@ -238,12 +238,23 @@ module SMESH * \param theFace - ID of face whose orientation is checked. * It can be < 1 then \a thePoint is used to find a face. * \param thePoint - is used to find a face if \a theFace < 1. - * \return number of reoriented elements. + * \return number of reoriented faces. */ long Reorient2D(in SMESH_IDSource the2Dgroup, in DirStruct theDirection, in long theFace, in PointStruct thePoint) raises (SALOME::SALOME_Exception); + /*! + * \brief Reorient faces basing on orientation of adjacent volumes. + * \param faces - a list of objects containing face to reorient + * \param volumes - an object containing volumes. + * \param outsideNormal - to orient faces to have their normal + * pointing either \a outside or \a inside the adjacent volumes. + * \return number of reoriented faces. + */ + long Reorient2DBy3D(in ListOfIDSources faces, + in SMESH_IDSource volumes, + in boolean outsideNormal) raises (SALOME::SALOME_Exception); /*! * \brief Fuse neighbour triangles into quadrangles. diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index f55e54a70..6bab9ef29 100755 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -205,6 +205,7 @@ SET(SMESH_RESOURCES_FILES mesh_min_dist.png reorient_faces_point.png reorient_faces_face.png + reorient_faces_volume.png mesh_ball.png mesh_measure_basic_props.png mesh_measure_length.png diff --git a/resources/reorient_faces_volume.png b/resources/reorient_faces_volume.png new file mode 100644 index 000000000..e58bdb6dc Binary files /dev/null and b/resources/reorient_faces_volume.png differ diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index 6bdd80cac..e216b2e74 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -1243,6 +1243,92 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, return nbReori; } +//================================================================================ +/*! + * \brief Reorient faces basing on orientation of adjacent volumes. + * \param theFaces - faces to reorient. If empty, all mesh faces are treated. + * \param theVolumes - reference volumes. + * \param theOutsideNormal - to orient faces to have their normal + * pointing either \a outside or \a inside the adjacent volumes. + * \return number of reoriented faces. + */ +//================================================================================ + +int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces, + TIDSortedElemSet & theVolumes, + const bool theOutsideNormal) +{ + int nbReori = 0; + + SMDS_ElemIteratorPtr faceIt; + if ( theFaces.empty() ) + faceIt = GetMeshDS()->elementsIterator( SMDSAbs_Face ); + else + faceIt = elemSetIterator( theFaces ); + + vector< const SMDS_MeshNode* > faceNodes; + TIDSortedElemSet checkedVolumes; + set< const SMDS_MeshNode* > faceNodesSet; + SMDS_VolumeTool volumeTool; + + while ( faceIt->more() ) // loop on given faces + { + const SMDS_MeshElement* face = faceIt->next(); + if ( face->GetType() != SMDSAbs_Face ) + continue; + + const int nbCornersNodes = face->NbCornerNodes(); + faceNodes.assign( face->begin_nodes(), face->end_nodes() ); + + checkedVolumes.clear(); + SMDS_ElemIteratorPtr vIt = faceNodes[ 0 ]->GetInverseElementIterator( SMDSAbs_Volume ); + while ( vIt->more() ) + { + const SMDS_MeshElement* volume = vIt->next(); + + if ( !checkedVolumes.insert( volume ).second ) + continue; + if ( !theVolumes.empty() && !theVolumes.count( volume )) + continue; + + // is volume adjacent? + bool allNodesCommon = true; + for ( int iN = 1; iN < nbCornersNodes && allNodesCommon; ++iN ) + allNodesCommon = ( volume->GetNodeIndex( faceNodes[ iN ]) > -1 ); + if ( !allNodesCommon ) + continue; + + // get nodes of a corresponding volume facet + faceNodesSet.clear(); + faceNodesSet.insert( faceNodes.begin(), faceNodes.end() ); + volumeTool.Set( volume ); + int facetID = volumeTool.GetFaceIndex( faceNodesSet ); + if ( facetID < 0 ) continue; + volumeTool.SetExternalNormal(); + const SMDS_MeshNode** facetNodes = volumeTool.GetFaceNodes( facetID ); + + // compare order of faceNodes and facetNodes + const int iQ = 1 + ( nbCornersNodes < faceNodes.size() ); + int iNN[2]; + for ( int i = 0; i < 2; ++i ) + { + const SMDS_MeshNode* n = facetNodes[ i*iQ ]; + for ( int iN = 0; iN < nbCornersNodes; ++iN ) + if ( faceNodes[ iN ] == n ) + { + iNN[ i ] = iN; + break; + } + } + bool isOutside = Abs( iNN[0]-iNN[1] ) == 1 ? iNN[0] < iNN[1] : iNN[0] > iNN[1]; + if ( isOutside != theOutsideNormal ) + nbReori += Reorient( face ); + } + } // loop on given faces + + return nbReori; +} + //======================================================================= //function : getBadRate //purpose : diff --git a/src/SMESH/SMESH_MeshEditor.hxx b/src/SMESH/SMESH_MeshEditor.hxx index c8f821f4e..5adb43a41 100644 --- a/src/SMESH/SMESH_MeshEditor.hxx +++ b/src/SMESH/SMESH_MeshEditor.hxx @@ -126,6 +126,12 @@ public: // Reverse theFaces whose orientation to be same as that of theFace // oriented according to theDirection. Return nb of reoriented faces + int Reorient2DBy3D (TIDSortedElemSet & theFaces, + TIDSortedElemSet & theVolumes, + const bool theOutsideNormal); + // Reorient faces basing on orientation of adjacent volumes. + // Return nb of reoriented faces + /*! * \brief Fuse neighbour triangles into quadrangles. * \param theElems - The triangles to be fused. diff --git a/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx b/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx index aee6f62d7..41e341cca 100644 --- a/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx @@ -92,8 +92,8 @@ #define SPACING 6 #define MARGIN 11 -enum { CONSTRUCTOR_POINT=0, CONSTRUCTOR_FACE, - EObject, EPoint, EFace, EDirection }; +enum { CONSTRUCTOR_POINT=0, CONSTRUCTOR_FACE, CONSTRUCTOR_VOLUME, + EObject, EPoint, EFace, EDirection, EVolumes }; //======================================================================= /*! @@ -131,6 +131,7 @@ QWidget* SMESHGUI_ReorientFacesDlg::createMainFrame (QWidget* theParent) QPixmap iconReoriPoint (resMgr()->loadPixmap("SMESH", tr("ICON_DLG_REORIENT2D_POINT"))); QPixmap iconReoriFace (resMgr()->loadPixmap("SMESH", tr("ICON_DLG_REORIENT2D_FACE"))); + QPixmap iconReoriVolum (resMgr()->loadPixmap("SMESH", tr("ICON_DLG_REORIENT2D_VOLUME"))); QGroupBox* aConstructorBox = new QGroupBox(tr("REORIENT_FACES"), aFrame); myConstructorGrp = new QButtonGroup(aConstructorBox); @@ -149,6 +150,11 @@ QWidget* SMESHGUI_ReorientFacesDlg::createMainFrame (QWidget* theParent) aConstructorGrpLayout->addWidget(aFaceBut); myConstructorGrp->addButton(aFaceBut, CONSTRUCTOR_FACE); + QRadioButton* aVolBut= new QRadioButton(aConstructorBox); + aVolBut->setIcon(iconReoriVolum); + aConstructorGrpLayout->addWidget(aVolBut); + myConstructorGrp->addButton(aVolBut, CONSTRUCTOR_VOLUME); + // Create other controls setObjectPixmap( "SMESH", tr( "ICON_SELECT" ) ); @@ -157,17 +163,22 @@ QWidget* SMESHGUI_ReorientFacesDlg::createMainFrame (QWidget* theParent) createObject( tr("POINT") , aFrame, EPoint ); createObject( tr("FACE") , aFrame, EFace ); createObject( tr("DIRECTION"), aFrame, EDirection ); + createObject( tr("VOLUMES"), aFrame, EVolumes ); setNameIndication( EObject, OneName ); setNameIndication( EFace, OneName ); setReadOnly( EFace, false ); if ( QLineEdit* le = qobject_cast( objectWg( EFace, Control ) )) le->setValidator( new SMESHGUI_IdValidator( this,1 )); - const int width = aFaceBut->fontMetrics().width( tr("DIRECTION")); + int width = aFaceBut->fontMetrics().width( tr("DIRECTION")); objectWg( EDirection, Label )->setFixedWidth( width ); objectWg( EObject , Label )->setFixedWidth( width ); objectWg( EPoint , Label )->setFixedWidth( width ); objectWg( EFace , Label )->setFixedWidth( width ); + objectWg( EVolumes , Label )->setFixedWidth( width ); + + myOutsideChk = new QCheckBox( tr("OUTSIDE_VOLUME_NORMAL"), aFrame); + myOutsideChk->setChecked( true ); QLabel* aXLabel = new QLabel(tr("SMESH_X"), aFrame); myX = new SMESHGUI_SpinBox(aFrame); @@ -197,6 +208,15 @@ QWidget* SMESHGUI_ReorientFacesDlg::createMainFrame (QWidget* theParent) myDY->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision"); myDZ->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision"); + width = Max( aFaceBut->fontMetrics().width( tr("SMESH_X")), + aFaceBut->fontMetrics().width( tr("SMESH_DX"))); + aXLabel->setFixedWidth( width ); + aYLabel->setFixedWidth( width ); + aZLabel->setFixedWidth( width ); + aDXLabel->setFixedWidth( width ); + aDYLabel->setFixedWidth( width ); + aDZLabel->setFixedWidth( width ); + // Layouting QGroupBox* anObjectGrp = new QGroupBox(tr("FACES"), aFrame); @@ -213,12 +233,12 @@ QWidget* SMESHGUI_ReorientFacesDlg::createMainFrame (QWidget* theParent) objectWg( EPoint, Control )->hide(); aPointGrpLayout->addWidget( objectWg( EPoint, Label ) ); aPointGrpLayout->addWidget( objectWg( EPoint, Btn ) ); - aPointGrpLayout->addWidget( aXLabel ); - aPointGrpLayout->addWidget( myX ); - aPointGrpLayout->addWidget( aYLabel ); - aPointGrpLayout->addWidget( myY ); - aPointGrpLayout->addWidget( aZLabel ); - aPointGrpLayout->addWidget( myZ ); + aPointGrpLayout->addWidget( aXLabel, 0 ); + aPointGrpLayout->addWidget( myX, 1 ); + aPointGrpLayout->addWidget( aYLabel, 0 ); + aPointGrpLayout->addWidget( myY, 1 ); + aPointGrpLayout->addWidget( aZLabel, 0 ); + aPointGrpLayout->addWidget( myZ, 1 ); myFaceFrm = new QFrame(aFrame); QHBoxLayout* aFaceGrpLayout = new QHBoxLayout(myFaceFrm); @@ -227,25 +247,35 @@ QWidget* SMESHGUI_ReorientFacesDlg::createMainFrame (QWidget* theParent) aFaceGrpLayout->addWidget( objectWg( EFace, Btn ) ); aFaceGrpLayout->addWidget( objectWg( EFace, Control ) ); - QFrame* aDirectFrm = new QFrame(aFrame); - QHBoxLayout* aDirectGrpLayout = new QHBoxLayout(aDirectFrm); + myVolumFrm = new QFrame(aFrame); + QGridLayout* aVolumGrpLayout = new QGridLayout(myVolumFrm); + aVolumGrpLayout->setMargin(0); + aVolumGrpLayout->setSpacing(SPACING); + aVolumGrpLayout->addWidget( objectWg( EVolumes, Label ), 0, 0 ); + aVolumGrpLayout->addWidget( objectWg( EVolumes, Btn ), 0, 1 ); + aVolumGrpLayout->addWidget( objectWg( EVolumes, Control ), 0, 2 ); + aVolumGrpLayout->addWidget( myOutsideChk, 1, 0, 1, 3 ); + + myDirFrm = new QFrame(aFrame); + QHBoxLayout* aDirectGrpLayout = new QHBoxLayout(myDirFrm); aDirectGrpLayout->setMargin(0); objectWg( EDirection, Control )->hide(); aDirectGrpLayout->addWidget( objectWg( EDirection, Label ) ); aDirectGrpLayout->addWidget( objectWg( EDirection, Btn ) ); - aDirectGrpLayout->addWidget(aDXLabel ); - aDirectGrpLayout->addWidget(myDX ); - aDirectGrpLayout->addWidget(aDYLabel ); - aDirectGrpLayout->addWidget(myDY ); - aDirectGrpLayout->addWidget(aDZLabel ); - aDirectGrpLayout->addWidget(myDZ ); + aDirectGrpLayout->addWidget( aDXLabel, 0 ); + aDirectGrpLayout->addWidget( myDX, 1 ); + aDirectGrpLayout->addWidget( aDYLabel, 0 ); + aDirectGrpLayout->addWidget( myDY, 1 ); + aDirectGrpLayout->addWidget( aDZLabel, 0 ); + aDirectGrpLayout->addWidget( myDZ, 1 ); QGroupBox* anOrientGrp = new QGroupBox(tr("ORIENTATION"), aFrame); QVBoxLayout* anOrientGrpLayout = new QVBoxLayout ( anOrientGrp ); anOrientGrpLayout->addWidget(myPointFrm); anOrientGrpLayout->addWidget(myFaceFrm); - anOrientGrpLayout->addWidget(aDirectFrm); + anOrientGrpLayout->addWidget(myVolumFrm); + anOrientGrpLayout->addWidget(myDirFrm); QVBoxLayout* aLay = new QVBoxLayout(aFrame); @@ -269,15 +299,27 @@ void SMESHGUI_ReorientFacesDlg::constructorChange(int id) if ( id == CONSTRUCTOR_FACE ) { myPointFrm->hide(); + myVolumFrm->hide(); myFaceFrm->show(); + myDirFrm->show(); activateObject( EFace ); } - else + else if ( id == CONSTRUCTOR_POINT ) { myFaceFrm->hide(); + myVolumFrm->hide(); myPointFrm->show(); + myDirFrm->show(); activateObject( EPoint ); } + else // CONSTRUCTOR_VOLUME + { + myFaceFrm->hide(); + myPointFrm->hide(); + myDirFrm->hide(); + myVolumFrm->show(); + activateObject( EVolumes ); + } } //================================================================================ @@ -373,6 +415,7 @@ void SMESHGUI_ReorientFacesOp::onActivateObject( int what ) SMESH::SetPickable(); break; case EObject: + case EVolumes: SMESH::SetPointRepresentation(false); setSelectionMode( ActorSelection ); break; @@ -406,6 +449,14 @@ SUIT_SelectionFilter* SMESHGUI_ReorientFacesOp::createFilter( const int what ) c filters.append( new SMESH_TypeFilter( SMESH::GROUP_FACE )); return new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR ); } + case EVolumes: + { + QList filters; + filters.append( new SMESH_TypeFilter( SMESH::MESH )); + filters.append( new SMESH_TypeFilter( SMESH::SUBMESH_SOLID )); + filters.append( new SMESH_TypeFilter( SMESH::GROUP_VOLUME )); + return new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR ); + } case EPoint: { QList filters; @@ -433,6 +484,12 @@ void SMESHGUI_ReorientFacesOp::selectionDone() if ( !myDlg->isVisible() || !myDlg->isEnabled() ) return; + if ( mySelectionMode == EVolumes ) + { + SMESHGUI_SelectionOp::selectionDone(); + return; + } + myDlg->clearSelection( mySelectionMode ); SALOME_ListIO aList; @@ -603,29 +660,45 @@ bool SMESHGUI_ReorientFacesOp::onApply() try { SUIT_OverrideCursor wc; + SMESH::SMESH_Mesh_var aMesh = myObject->GetMesh(); if ( aMesh->_is_nil() ) return false; - SMESH::DirStruct direction; - direction.PS.x = myDlg->myDX->GetValue(); - direction.PS.y = myDlg->myDY->GetValue(); - direction.PS.z = myDlg->myDZ->GetValue(); - - long face = myDlg->objectText( EFace ).toInt(); - if ( myDlg->myConstructorGrp->checkedId() == CONSTRUCTOR_POINT ) - face = -1; - - SMESH::PointStruct point; - point.x = myDlg->myX->GetValue(); - point.y = myDlg->myY->GetValue(); - point.z = myDlg->myZ->GetValue(); - SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor(); if (aMeshEditor->_is_nil()) return false; - aMesh->SetParameters( aParameters.join(":").toLatin1().constData() ); + int aResult = 0; + if ( myDlg->myConstructorGrp->checkedId() == CONSTRUCTOR_VOLUME ) + { + SMESH::ListOfIDSources_var faceGroups = new SMESH::ListOfIDSources; + faceGroups->length(1); + faceGroups[0] = myObject; + + bool outsideNormal = myDlg->myOutsideChk->isChecked(); + + aResult = aMeshEditor->Reorient2DBy3D( faceGroups, myVolumeObj, outsideNormal ); + } + else + { + SMESH::DirStruct direction; + direction.PS.x = myDlg->myDX->GetValue(); + direction.PS.y = myDlg->myDY->GetValue(); + direction.PS.z = myDlg->myDZ->GetValue(); + + long face = myDlg->objectText( EFace ).toInt(); + if ( myDlg->myConstructorGrp->checkedId() == CONSTRUCTOR_POINT ) + face = -1; + + SMESH::PointStruct point; + point.x = myDlg->myX->GetValue(); + point.y = myDlg->myY->GetValue(); + point.z = myDlg->myZ->GetValue(); + + aMesh->SetParameters( aParameters.join(":").toLatin1().constData() ); + + aResult = aMeshEditor->Reorient2D( myObject, direction, face, point ); + } - int aResult = aMeshEditor->Reorient2D( myObject, direction, face, point ); if (aResult) { SALOME_ListIO aList; @@ -673,6 +746,27 @@ bool SMESHGUI_ReorientFacesOp::isValid( QString& msg ) return false; } + // check volume object + if ( myDlg->myConstructorGrp->checkedId() == CONSTRUCTOR_VOLUME ) + { + objectEntry = myDlg->selectedObject( EVolumes ); + _PTR(SObject) pSObject = studyDS()->FindObjectID( objectEntry.toLatin1().data() ); + myVolumeObj = SMESH::SObjectToInterface< SMESH::SMESH_IDSource>( pSObject ); + if ( myVolumeObj->_is_nil() ) + { + msg = tr("NO_VOLUME_OBJECT_SELECTED"); + return false; + } + bool hasVolumes = false; + types = myVolumeObj->GetTypes(); + for ( size_t i = 0; i < types->length() && !hasVolumes; ++i ) + hasVolumes = ( types[i] == SMESH::VOLUME ); + if ( !hasVolumes ) + { + msg = tr("NO_VOLUMES"); + return false; + } + } // check vector gp_Vec vec( myDlg->myDX->GetValue(), myDlg->myDY->GetValue(), diff --git a/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.h b/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.h index 400850b89..e0908171b 100644 --- a/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.h +++ b/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.h @@ -33,12 +33,13 @@ #include "SMESHGUI_SelectionOp.h" class QButtonGroup; +class QCheckBox; class QLineEdit; class SMESHGUI_SpinBox; class SMESHGUI_ReorientFacesDlg; /*! - * \brief Operation to reorient faces acoording to vector + * \brief Operation to reorient faces acoording to some criterion */ class SMESHGUI_EXPORT SMESHGUI_ReorientFacesOp: public SMESHGUI_SelectionOp { @@ -76,6 +77,7 @@ private: int mySelectionMode; SMESH::SMESH_IDSource_var myObject; + SMESH::SMESH_IDSource_var myVolumeObj; }; /*! @@ -98,6 +100,9 @@ private: QButtonGroup* myConstructorGrp; QFrame* myFaceFrm; QFrame* myPointFrm; + QFrame* myDirFrm; + QFrame* myVolumFrm; + QCheckBox* myOutsideChk; SMESHGUI_SpinBox* myX; SMESHGUI_SpinBox* myY; SMESHGUI_SpinBox* myZ; diff --git a/src/SMESHGUI/SMESH_images.ts b/src/SMESHGUI/SMESH_images.ts index b27b101ca..63187d137 100644 --- a/src/SMESHGUI/SMESH_images.ts +++ b/src/SMESHGUI/SMESH_images.ts @@ -427,6 +427,10 @@ ICON_DLG_REORIENT2D_FACE reorient_faces_face.png + + ICON_DLG_REORIENT2D_VOLUME + reorient_faces_volume.png + ICON_REORIENT_2D reorient_faces_face.png diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index 7e1bb3da3..fcb37740a 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -470,15 +470,15 @@ TOP_REORIENT_2D - Reorient faces by vector + Reorient faces MEN_REORIENT_2D - Reorient faces by vector + Reorient faces STB_REORIENT_2D - Reorient faces by vector + Reorient faces TOP_FIND_ELEM @@ -7656,7 +7656,7 @@ as they are of improper type: SMESHGUI_ReorientFacesDlg CAPTION - Reorient faces by vector + Reorient faces REORIENT_FACES @@ -7686,6 +7686,14 @@ as they are of improper type: ORIENTATION Orientation + + VOLUMES + Volumes + + + OUTSIDE_VOLUME_NORMAL + Face normal outside volume + SMESHGUI_ReorientFacesOp @@ -7693,10 +7701,18 @@ as they are of improper type: NO_OBJECT_SELECTED No object selected + + NO_VOLUME_OBJECT_SELECTED + No volume object selected + NO_FACES Object includes no faces + + NO_VOLUMES + Volume object includes no volumes + ZERO_SIZE_VECTOR Zero size vector diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index 9a7550d18..564632744 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -2369,7 +2369,7 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand) "AddNode","Add0DElement","AddEdge","AddFace","AddPolygonalFace","AddBall", "AddVolume","AddPolyhedralVolume","AddPolyhedralVolumeByFaces", "MoveNode", "MoveClosestNodeToPoint", - "InverseDiag","DeleteDiag","Reorient","ReorientObject", + "InverseDiag","DeleteDiag","Reorient","ReorientObject","Reorient2DBy3D", "TriToQuad","TriToQuadObject", "QuadTo4Tri", "SplitQuad","SplitQuadObject", "BestSplit","Smooth","SmoothObject","SmoothParametric","SmoothParametricObject", "ConvertToQuadratic","ConvertFromQuadratic","RenumberNodes","RenumberElements", diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index 9de57c975..fd69f00f6 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -1645,7 +1645,7 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup, TIDSortedElemSet elements; prepareIdSource( the2Dgroup ); if ( !idSourceToSet( the2Dgroup, getMeshDS(), elements, SMDSAbs_Face, /*emptyIfIsMesh=*/1)) - THROW_SALOME_CORBA_EXCEPTION("No faces in given group", SALOME::BAD_PARAM); + return 0;//THROW_SALOME_CORBA_EXCEPTION("No faces in given group", SALOME::BAD_PARAM); const SMDS_MeshElement* face = 0; @@ -1710,6 +1710,55 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup, return 0; } +//======================================================================= +//function : Reorient2DBy3D +//purpose : Reorient faces basing on orientation of adjacent volumes. +//======================================================================= + +CORBA::Long SMESH_MeshEditor_i::Reorient2DBy3D(const SMESH::ListOfIDSources& faceGroups, + SMESH::SMESH_IDSource_ptr volumeGroup, + CORBA::Boolean outsideNormal) + throw (SALOME::SALOME_Exception) +{ + SMESH_TRY; + initData(); + + TIDSortedElemSet volumes; + prepareIdSource( volumeGroup ); + if ( !idSourceToSet( volumeGroup, getMeshDS(), volumes, SMDSAbs_Volume, /*emptyIfIsMesh=*/1)) + THROW_SALOME_CORBA_EXCEPTION("No volumes in a given object", SALOME::BAD_PARAM); + + int nbReori = 0; + for ( size_t i = 0; i < faceGroups.length(); ++i ) + { + SMESH::SMESH_IDSource_ptr faceGrp = faceGroups[i].in(); + prepareIdSource( faceGrp ); + + TIDSortedElemSet faces; + if ( !idSourceToSet( faceGrp, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/1) && + faceGroups.length() == 1 ) + ; //THROW_SALOME_CORBA_EXCEPTION("No faces in a given object", SALOME::BAD_PARAM); + + nbReori += getEditor().Reorient2DBy3D( faces, volumes, outsideNormal ); + + if ( faces.empty() ) // all faces in the mesh treated + break; + } + + if ( nbReori ) { + declareMeshModified( /*isReComputeSafe=*/false ); + } + TPythonDump() << this << ".Reorient2DBy3D( " + << faceGroups << ", " + << volumeGroup << ", " + << outsideNormal << " )"; + + return nbReori; + + SMESH_CATCH( SMESH::throwCorbaException ); + return 0; +} + //============================================================================= /*! * \brief Fuse neighbour triangles into quadrangles. diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx index ead3048b0..bce7c4c4c 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.hxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx @@ -203,6 +203,18 @@ public: const SMESH::DirStruct& theDirection, CORBA::Long theFace, const SMESH::PointStruct& thePoint) throw (SALOME::SALOME_Exception); + /*! + * \brief Reorient faces basing on orientation of adjacent volumes. + * \param faces - a list of objects containing face to reorient + * \param volumes - an object containing volumes. + * \param outsideNormal - to orient faces to have their normal + * pointing either \a outside or \a inside the adjacent volumes. + * \return number of reoriented faces. + */ + CORBA::Long Reorient2DBy3D(const SMESH::ListOfIDSources & faces, + SMESH::SMESH_IDSource_ptr volumes, + CORBA::Boolean outsideNormal) + throw (SALOME::SALOME_Exception); // Split/Join faces CORBA::Boolean TriToQuad (const SMESH::long_array & IDsOfElements, diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index 767a5ef14..a51e40ce8 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -2964,6 +2964,37 @@ class Mesh: theFace = -1 return self.editor.Reorient2D( the2DObject, theDirection, theFace, thePoint ) + ## Reorient faces according to adjacent volumes. + # @param the2DObject is a mesh, sub-mesh, group or list of + # either IDs of faces or face groups. + # @param the3DObject is a mesh, sub-mesh, group or list of IDs of volumes. + # @param theOutsideNormal to orient faces to have their normals + # pointing either \a outside or \a inside the adjacent volumes. + # @return number of reoriented faces. + # @ingroup l2_modif_changori + def Reorient2DBy3D(self, the2DObject, the3DObject, theOutsideNormal=True ): + unRegister = genObjUnRegister() + # check the2DObject + if not isinstance( the2DObject, list ): + the2DObject = [ the2DObject ] + elif the2DObject and isinstance( the2DObject[0], int ): + the2DObject = self.GetIDSource( the2DObject, SMESH.FACE ) + unRegister.set( the2DObject ) + the2DObject = [ the2DObject ] + for i,obj2D in enumerate( the2DObject ): + if isinstance( obj2D, Mesh ): + the2DObject[i] = obj2D.GetMesh() + if isinstance( obj2D, list ): + the2DObject[i] = self.GetIDSource( obj2D, SMESH.FACE ) + unRegister.set( the2DObject[i] ) + # check the3DObject + if isinstance( the3DObject, Mesh ): + the3DObject = the3DObject.GetMesh() + if isinstance( the3DObject, list ): + the3DObject = self.GetIDSource( the3DObject, SMESH.VOLUME ) + unRegister.set( the3DObject ) + return self.editor.Reorient2DBy3D( the2DObject, the3DObject, theOutsideNormal ) + ## Fuses the neighbouring triangles into quadrangles. # @param IDsOfElements The triangles to be fused, # @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, used to