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.
+
+
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
+
found by proximity to a given point or
+
specified explicitly.
+
+
To reorient faces with relation to adjacent volumes.
+
Orientation of a face is changed by reverting the order of its nodes.
To change orientation of faces:
-
In the \b Modification menu select Reorient faces by
- vector item or click Reorient faces by
- vector button in the toolbar.
+
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."
In this dialog
-
Specify the way of selection of the control face: by point or
- explicitly.
-
Select the \b Object (mesh, sub-mesh or a group of faces) containing faces to reorient in the Object Browser or in the 3D Viewer.
-
Specify the coordinates of the \b Point by which the control face
- will be found or of the control \b Face itself. You can easy specify the \b
- Point by either picking a node in the 3D Viewer or selecting a vertex
- in the Object Browser. It is possible to pick the \b Face by mouse in
- the 3D Viewer or enter its ID.
-
Set up the \b Direction vector to be compared with the normal of the
- control face. If you pick a node in the 3D Viewer then the \b Direction
- vector will go from the coordinate system origin to the selected node.
- If you pick two nodes (holding Shift button) then the \b Direction vector
- will go from the first to the second node.
+
Specify either of the tree operation modes.
+
Select the \b Object (mesh, sub-mesh or group)
+ containing faces to reorient, in the Object Browser or in the 3D
+ Viewer.
+
To reorient according to vector:
+
Specify the coordinates of the \b Point by which the control face
+ will be found or the control \b Face itself. You can easy specify the \b
+ Point by either picking a node in the 3D Viewer or selecting a vertex
+ in the Object Browser. It is possible to pick the \b Face by mouse in
+ the 3D Viewer or enter its ID.
+
Set up the \b Direction vector to be compared with the normal of the
+ control face. If you pick a node in the 3D Viewer then the \b Direction
+ vector will go from the coordinate system origin to the selected node.
+ If you pick two nodes (holding Shift button) then the \b Direction vector
+ will go from the first to the second node.
+
To reorient according to volumes:
+
Select an object (mesh, sub-mesh or group) containing
+ reference \b Volumes, in the Object Browser or in the 3D
+ Viewer.
+
Specify whether face normals should point outside or inside
+ the reference volumes using Face normal outside volume
+ check-box.
@@ -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 @@
reorient_faces_face.png
+
+
+ reorient_faces_volume.png
+ 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 @@
- Reorient faces by vector
+ Reorient faces
- Reorient faces by vector
+ Reorient faces
- Reorient faces by vector
+ Reorient faces
@@ -7656,7 +7656,7 @@ as they are of improper type:
SMESHGUI_ReorientFacesDlg
- Reorient faces by vector
+ Reorient faces
@@ -7686,6 +7686,14 @@ as they are of improper type:
Orientation
+
+
+ Volumes
+
+
+
+ Face normal outside volume
+ SMESHGUI_ReorientFacesOp
@@ -7693,10 +7701,18 @@ as they are of improper type:
No object selected
+
+
+ No volume object selected
+ Object includes no faces
+
+
+ Volume object includes no volumes
+ 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