diff --git a/doc/salome/examples/transforming_meshes_ex13.py b/doc/salome/examples/transforming_meshes_ex13.py index 94b6f7f22..d4b553963 100644 --- a/doc/salome/examples/transforming_meshes_ex13.py +++ b/doc/salome/examples/transforming_meshes_ex13.py @@ -33,6 +33,10 @@ group = mesh.Group( faces[1] ) vec = geompy.MakeVectorDXDYDZ( 1, 1, 1 ) +# ============ +# Reorient2D() +# ============ + # Each of arguments of Reorient2D() function can be of different types: # # 2DObject - the whole mesh @@ -53,6 +57,19 @@ 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)) +# ======================== +# Reorient2DByNeighbours() +# ======================== + +# Use faces of 'group' as a reference to reorient equally all faces +mesh.Reorient2DByNeighbours([mesh], [group]) + +# Orient equally face on 'group', but not define which orientation is correct +mesh.Reorient2DByNeighbours([group]) + +# ================= +# Reorient2DBy3D() +# ================= # Use Reorient2DBy3D() to orient faces of 2 geom faces to have their normal pointing inside volumes diff --git a/doc/salome/gui/SMESH/images/reorient_2d_refgroup.png b/doc/salome/gui/SMESH/images/reorient_2d_refgroup.png new file mode 100644 index 000000000..f080f460b Binary files /dev/null and b/doc/salome/gui/SMESH/images/reorient_2d_refgroup.png differ diff --git a/doc/salome/gui/SMESH/images/reorient_faces_point.png b/doc/salome/gui/SMESH/images/reorient_faces_point.png new file mode 100644 index 000000000..63fae7233 Binary files /dev/null and b/doc/salome/gui/SMESH/images/reorient_faces_point.png differ diff --git a/doc/salome/gui/SMESH/images/reorient_faces_ref_groups.png b/doc/salome/gui/SMESH/images/reorient_faces_ref_groups.png new file mode 100644 index 000000000..f9cf53bd9 Binary files /dev/null and b/doc/salome/gui/SMESH/images/reorient_faces_ref_groups.png differ diff --git a/doc/salome/gui/SMESH/images/reorient_faces_volume.png b/doc/salome/gui/SMESH/images/reorient_faces_volume.png new file mode 100644 index 000000000..e58bdb6dc Binary files /dev/null and b/doc/salome/gui/SMESH/images/reorient_faces_volume.png differ diff --git a/doc/salome/gui/SMESH/input/modules.rst b/doc/salome/gui/SMESH/input/modules.rst index 12133771b..41915c4f1 100644 --- a/doc/salome/gui/SMESH/input/modules.rst +++ b/doc/salome/gui/SMESH/input/modules.rst @@ -449,6 +449,7 @@ Changing orientation of elements Mesh.Reorient Mesh.ReorientObject Mesh.Reorient2D + Mesh.Reorient2DByNeighbours Mesh.Reorient2DBy3D Uniting triangles diff --git a/doc/salome/gui/SMESH/input/reorient_faces.rst b/doc/salome/gui/SMESH/input/reorient_faces.rst index 82982dd9a..87d510007 100644 --- a/doc/salome/gui/SMESH/input/reorient_faces.rst +++ b/doc/salome/gui/SMESH/input/reorient_faces.rst @@ -6,22 +6,33 @@ Orient faces ************ This operation allows fixing the orientation of a set of faces in the following ways: - + * The required orientation of a set of neighboring faces can be defined by a vector giving the direction of a normal to a certain face. Since the direction of face normals in the set can be even opposite, it is necessary to specify a *control* face, the normal to which will be compared with the vector. This face can be either: * found by proximity to a given point, or * specified explicitly. +* The required orientation is given by faces of specified reference groups or/and sub-meshes. The reference groups can be omitted, then orientation of an arbitrary selected face to orient defines common orientation. * Alternatively, the faces can be oriented relatively to the adjacent volumes. The orientation of a face is changed by reverting the order of its nodes. *To set orientation of faces:* -.. |img| image:: ../images/reorient_faces_face.png +.. |imgfac| image:: ../images/reorient_faces_face.png +.. |imgpnt| image:: ../images/reorient_faces_point.png +.. |imggrp| image:: ../images/reorient_faces_ref_groups.png +.. |imgvol| image:: ../images/reorient_faces_volume.png -#. In the **Modification** menu select **Reorient faces** item or click *"Reorient faces"* button |img| in the toolbar. +#. In the **Modification** menu select **Reorient faces** item or click *"Reorient faces"* button |imgfac| in the toolbar. #. In the "Reorient faces" dialog box - * Select the **Object** (mesh, sub-mesh or group) containing faces to reorient, in the Object Browser or in the 3D Viewer. + * Select a way to define orientation: + + * |imgpnt| - by specifying a point and a vector + * |imgfac| - by specifying a face and a vector + * |imggrp| - by specifying reference face groups + * |imgvol| - by specifying reference volume groups + + * Select the **Object(s)** (mesh, groups and/or sub-meshes) containing faces to reorient, in the Object Browser or in the 3D Viewer. * To reorient by direction of the face normal: * Specify the coordinates of the **Point** by which the control face will be found. You can specify the **Point** by picking a node in the 3D Viewer or selecting a vertex in the Object Browser. @@ -37,7 +48,7 @@ The orientation of a face is changed by reverting the order of its nodes. .. centered:: The orientation of adjacent faces is chosen according to a vector. The control face is found by point. - * In the second mode it is possible to pick the **Face** by mouse in the 3D Viewer or directly input the **Face** ID in the corresponding field. + * In the second mode it is possible to pick the **Face** by mouse in the 3D Viewer or directly enter the **Face** ID in the corresponding field. .. image:: ../images/reorient_2d_face.png :align: center @@ -46,16 +57,27 @@ The orientation of a face is changed by reverting the order of its nodes. The orientation of adjacent faces is chosen according to a vector. The control face is explicitly given. - * In the third mode, the faces can be reoriented according to volumes: + * In the third mode, the faces can be reoriented equally to reference faces: + + * If necessary, select 2D **Reference objects** (groups or/and sub-meshes) containing the reference faces, in the Object Browser or in the 3D Viewer. This field can be left empty, then orientation of an arbitrary face will be used as a reference. + + + .. image:: ../images/reorient_2d_refgroup.png + :align: center + + .. centered:: + The orientation of faces is given by reference face groups and/or sub-meshes. + + * In the fourth mode, the faces can be reoriented according to volumes: * Select an object (mesh, sub-mesh or group) containing reference **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. - .. image:: ../images/reorient_2d_volume.png - :align: center + .. image:: ../images/reorient_2d_volume.png + :align: center - .. centered:: - The orientation of faces is chosen relatively to adjacent volumes. + .. centered:: + The orientation of faces is chosen relatively to adjacent volumes. #. Click the **Apply** or **Apply and Close** button to confirm the operation. diff --git a/idl/SMESH_MeshEditor.idl b/idl/SMESH_MeshEditor.idl index 26e73dfaf..69f159dc2 100644 --- a/idl/SMESH_MeshEditor.idl +++ b/idl/SMESH_MeshEditor.idl @@ -318,6 +318,19 @@ module SMESH in DirStruct theDirection, in long theFace, in PointStruct thePoint) raises (SALOME::SALOME_Exception); + /*! + * \brief Reorient faces contained in a list of \a objectFaces + * equally to faces contained in a list of \a referenceFaces. + * \param objectFaces - faces to reorient in a list including either + * the whole mesh or groups and/or sub-meshes. + * \param referenceFaces - correctly oriented faces in a list of groups and/or sub-meshes. + * It can be empty, then the 1st face in \a objectFaces is used as the reference. + * \return number of reoriented faces. + */ + long Reorient2DByNeighbours(in SMESH::ListOfIDSources objectFaces, + in SMESH::ListOfIDSources referenceFaces) + raises (SALOME::SALOME_Exception); + /*! * \brief Reorient faces basing on orientation of adjacent volumes. * \param faces - a list of objects containing face to reorient @@ -338,6 +351,7 @@ module SMESH * is still performed; theMaxAngle is measured in radians. * \return \c true in case of success, FALSE otherwise. */ + boolean TriToQuad (in smIdType_array IDsOfElements, in NumericalFunctor Criterion, in double MaxAngle) raises (SALOME::SALOME_Exception); diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index 6c6c90d80..7e0d62012 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -236,6 +236,7 @@ SET(SMESH_RESOURCES_FILES pattern_sample_3D.png reorient_faces_face.png reorient_faces_point.png + reorient_faces_ref_groups.png reorient_faces_volume.png scale.png scale_along_axes.png diff --git a/resources/reorient_faces_ref_groups.png b/resources/reorient_faces_ref_groups.png new file mode 100644 index 000000000..f9cf53bd9 Binary files /dev/null and b/resources/reorient_faces_ref_groups.png differ diff --git a/src/SMDS/SMDS_ElementFactory.cxx b/src/SMDS/SMDS_ElementFactory.cxx index c3ab97c8c..611511916 100644 --- a/src/SMDS/SMDS_ElementFactory.cxx +++ b/src/SMDS/SMDS_ElementFactory.cxx @@ -230,6 +230,18 @@ smIdType SMDS_ElementFactory::FromVtkToSmds( vtkIdType vtkID ) return vtkID + 1; } +//================================================================================ +/*! + * \brief Clear marked flag of all elements + */ +//================================================================================ + +void SMDS_ElementFactory::SetAllNotMarked() +{ + for ( SMDS_ElementChunk& chunk : myChunks ) + chunk.SetAllNotMarked(); +} + //================================================================================ /*! * \brief Mark the element as non-used @@ -727,6 +739,17 @@ void SMDS_ElementChunk::SetIsMarked( const SMDS_MeshElement* e, bool is ) myMarkedSet[ Index( e )] = is; } +//================================================================================ +/*! + * \brief Clear marked flag of all elements + */ +//================================================================================ + +void SMDS_ElementChunk::SetAllNotMarked() +{ + clearVector( myMarkedSet ); +} + //================================================================================ /*! * \brief Return SMDS_Position of a node on a shape diff --git a/src/SMDS/SMDS_ElementFactory.hxx b/src/SMDS/SMDS_ElementFactory.hxx index dcc00a307..92f22e55a 100644 --- a/src/SMDS/SMDS_ElementFactory.hxx +++ b/src/SMDS/SMDS_ElementFactory.hxx @@ -116,6 +116,8 @@ public: boost::shared_ptr< ElemIterator > GetShapeIterator( int shapeID, size_t nbElemsToReturn, const SMDS_MeshElement* sm1stElem ); + //! Clear marked flag of all elements + void SetAllNotMarked(); //! Mark the element as non-used void Free( const SMDS_MeshElement* ); @@ -441,6 +443,7 @@ public: bool IsMarked ( const SMDS_MeshElement* e ) const; void SetIsMarked( const SMDS_MeshElement* e, bool is ); + void SetAllNotMarked(); SMDS_PositionPtr GetPosition( const SMDS_MeshNode* n ) const; void SetPosition( const SMDS_MeshNode* n, const SMDS_PositionPtr& pos, int shapeID ); diff --git a/src/SMDS/SMDS_Mesh.cxx b/src/SMDS/SMDS_Mesh.cxx index 2e9924295..d26107218 100644 --- a/src/SMDS/SMDS_Mesh.cxx +++ b/src/SMDS/SMDS_Mesh.cxx @@ -1052,6 +1052,26 @@ bool SMDS_Mesh::RemoveSubMesh(const SMDS_Mesh * aMesh) return found; } +//======================================================================= +//function : SetAllNodesNotMarked +//purpose : Clear marked flag of all nodes +//======================================================================= + +void SMDS_Mesh::SetAllNodesNotMarked() +{ + myNodeFactory->SetAllNotMarked(); +} + +//======================================================================= +//function : SetAllCellsNotMarked +//purpose : Clear marked flag of all cells +//======================================================================= + +void SMDS_Mesh::SetAllCellsNotMarked() +{ + myCellFactory->SetAllNotMarked(); +} + //======================================================================= //function : ChangePolyhedronNodes //purpose : diff --git a/src/SMDS/SMDS_Mesh.hxx b/src/SMDS/SMDS_Mesh.hxx index c76f7d277..de50492f9 100644 --- a/src/SMDS/SMDS_Mesh.hxx +++ b/src/SMDS/SMDS_Mesh.hxx @@ -618,6 +618,9 @@ public: const std::vector& nodes, const std::vector& quantities); + void SetAllNodesNotMarked(); + void SetAllCellsNotMarked(); + //virtual void Renumber (const bool isNodes, const int startID = 1, const int deltaID = 1); // Renumber all nodes or elements. diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index f97e645dc..853d59b3e 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -1161,69 +1161,88 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem) /*! * \brief Reorient faces. * \param theFaces - the faces to reorient. If empty the whole mesh is meant - * \param theDirection - desired direction of normal of \a theFace - * \param theFace - one of \a theFaces that should be oriented according to - * \a theDirection and whose orientation defines orientation of other faces + * \param theDirection - desired direction of normal of \a theRefFaces. + * It can be (0,0,0) in order to keep orientation of \a theRefFaces. + * \param theRefFaces - correctly oriented faces whose orientation defines + * orientation of other faces. * \return number of reoriented faces. */ //================================================================================ -int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, - const gp_Dir& theDirection, - const SMDS_MeshElement * theFace) +int SMESH_MeshEditor::Reorient2D( TIDSortedElemSet & theFaces, + const gp_Vec& theDirection, + TIDSortedElemSet & theRefFaces, + bool theAllowNonManifold ) { int nbReori = 0; - if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori; if ( theFaces.empty() ) { - SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=true*/); + SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(); while ( fIt->more() ) theFaces.insert( theFaces.end(), fIt->next() ); + + if ( theFaces.empty() ) + return nbReori; } - // orient theFace according to theDirection - gp_XYZ normal; - SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false ); - if ( normal * theDirection.XYZ() < 0 ) - nbReori += Reorient( theFace ); + // orient theRefFaces according to theDirection + if ( theDirection.X() != 0 || theDirection.Y() != 0 || theDirection.Z() != 0 ) + for ( const SMDS_MeshElement* refFace : theRefFaces ) + { + gp_XYZ normal; + SMESH_MeshAlgos::FaceNormal( refFace, normal, /*normalized=*/false ); + if ( normal * theDirection.XYZ() < 0 ) + nbReori += Reorient( refFace ); + } - // Orient other faces + // mark reference faces + GetMeshDS()->SetAllCellsNotMarked(); + for ( const SMDS_MeshElement* refFace : theRefFaces ) + refFace->setIsMarked( true ); - set< const SMDS_MeshElement* > startFaces, visitedFaces; - TIDSortedElemSet avoidSet; - set< SMESH_TLink > checkedLinks; - pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew; + // erase reference faces from theFaces + for ( TIDSortedElemSet::iterator fIt = theFaces.begin(); fIt != theFaces.end(); ) + if ( (*fIt)->isMarked() ) + fIt = theFaces.erase( fIt ); + else + ++fIt; - if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces - theFaces.erase( theFace ); - startFaces.insert( theFace ); + if ( theRefFaces.empty() ) + { + theRefFaces.insert( *theFaces.begin() ); + theFaces.erase( theFaces.begin() ); + } + + // Orient theFaces + + // if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces + // theFaces.erase( theFace ); int nodeInd1, nodeInd2; - const SMDS_MeshElement* otherFace; + const SMDS_MeshElement* refFace, *otherFace; vector< const SMDS_MeshElement* > facesNearLink; vector< std::pair< int, int > > nodeIndsOfFace; + TIDSortedElemSet avoidSet, emptySet; + NCollection_Map< SMESH_TLink, SMESH_TLink > checkedLinks; - set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin(); - while ( !startFaces.empty() ) + while ( !theRefFaces.empty() ) { - startFace = startFaces.begin(); - theFace = *startFace; - startFaces.erase( startFace ); - if ( !visitedFaces.insert( theFace ).second ) - continue; + auto refFaceIt = theRefFaces.begin(); + refFace = *refFaceIt; + theRefFaces.erase( refFaceIt ); avoidSet.clear(); - avoidSet.insert(theFace); + avoidSet.insert( refFace ); - NLink link( theFace->GetNode( 0 ), (SMDS_MeshNode *) 0 ); + NLink link( refFace->GetNode( 0 ), nullptr ); - const int nbNodes = theFace->NbCornerNodes(); - for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace + const int nbNodes = refFace->NbCornerNodes(); + for ( int i = 0; i < nbNodes; ++i ) // loop on links of refFace { - link.second = theFace->GetNode(( i+1 ) % nbNodes ); - linkIt_isNew = checkedLinks.insert( link ); - if ( !linkIt_isNew.second ) + link.second = refFace->GetNode(( i+1 ) % nbNodes ); + bool isLinkVisited = checkedLinks.Contains( link ); + if ( isLinkVisited ) { // link has already been checked and won't be encountered more // if the group (theFaces) is manifold @@ -1231,28 +1250,41 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, } else { + checkedLinks.Add( link ); + facesNearLink.clear(); nodeIndsOfFace.clear(); + TIDSortedElemSet::iterator objFaceIt = theFaces.end(); + while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second, - theFaces, avoidSet, + emptySet, avoidSet, &nodeInd1, &nodeInd2 ))) - if ( otherFace != theFace) + { + if (( otherFace->isMarked() ) || // ref face + (( objFaceIt = theFaces.find( otherFace )) != theFaces.end() )) // object face { facesNearLink.push_back( otherFace ); nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 )); - avoidSet.insert( otherFace ); } + avoidSet.insert( otherFace ); + } if ( facesNearLink.size() > 1 ) { // NON-MANIFOLD mesh shell ! - // select a face most co-directed with theFace, + if ( !theAllowNonManifold ) + { + throw SALOME_Exception("Non-manifold topology of groups"); + } + // select a face most co-directed with refFace, // other faces won't be visited this time gp_XYZ NF, NOF; - SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false ); + SMESH_MeshAlgos::FaceNormal( refFace, NF, /*normalized=*/false ); double proj, maxProj = -1; - for ( size_t i = 0; i < facesNearLink.size(); ++i ) { + for ( size_t i = 0; i < facesNearLink.size(); ++i ) + { SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false ); - if (( proj = Abs( NF * NOF )) > maxProj ) { + if (( proj = Abs( NF * NOF )) > maxProj ) + { maxProj = proj; otherFace = facesNearLink[i]; nodeInd1 = nodeIndsOfFace[i].first; @@ -1260,9 +1292,9 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, } } // not to visit rejected faces - for ( size_t i = 0; i < facesNearLink.size(); ++i ) - if ( facesNearLink[i] != otherFace && theFaces.size() > 1 ) - visitedFaces.insert( facesNearLink[i] ); + // for ( size_t i = 0; i < facesNearLink.size(); ++i ) + // if ( facesNearLink[i] != otherFace && theFaces.size() > 1 ) + // visitedFaces.insert( facesNearLink[i] ); } else if ( facesNearLink.size() == 1 ) { @@ -1270,20 +1302,36 @@ int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, nodeInd1 = nodeIndsOfFace.back().first; nodeInd2 = nodeIndsOfFace.back().second; } - if ( otherFace && otherFace != theFace) + if ( otherFace ) { - // link must be reverse in otherFace if orientation to otherFace - // is same as that of theFace - if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 ) + // link must be reverse in otherFace if orientation of otherFace + // is same as that of refFace + if ( abs( nodeInd2 - nodeInd1 ) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 ) { + if ( otherFace->isMarked() ) + throw SALOME_Exception("Different orientation of reference faces"); nbReori += Reorient( otherFace ); } - startFaces.insert( otherFace ); + if ( !otherFace->isMarked() ) + { + theRefFaces.insert( otherFace ); + if ( objFaceIt != theFaces.end() ) + theFaces.erase( objFaceIt ); + } } } - std::swap( link.first, link.second ); // reverse the link + link.first = link.second; // reverse the link + + } // loop on links of refFace + + if ( theRefFaces.empty() && !theFaces.empty() ) + { + theRefFaces.insert( *theFaces.begin() ); + theFaces.erase( theFaces.begin() ); } - } + + } // while ( !theRefFaces.empty() ) + return nbReori; } diff --git a/src/SMESH/SMESH_MeshEditor.hxx b/src/SMESH/SMESH_MeshEditor.hxx index e9e13f796..6962f2c2d 100644 --- a/src/SMESH/SMESH_MeshEditor.hxx +++ b/src/SMESH/SMESH_MeshEditor.hxx @@ -158,11 +158,12 @@ public: bool Reorient (const SMDS_MeshElement * theElement); // Reverse theElement orientation - int Reorient2D (TIDSortedElemSet & theFaces, - const gp_Dir& theDirection, - const SMDS_MeshElement * theFace); - // Reverse theFaces whose orientation to be same as that of theFace - // oriented according to theDirection. Return nb of reoriented faces + int Reorient2D (TIDSortedElemSet & theFaces, + const gp_Vec& theDirection, + TIDSortedElemSet & theRefFaces, + bool theAllowNonManifold); + // Reverse theFaces whose orientation to be same as that of theRefFaces + // optionally oriented according to theDirection. Return nb of reoriented faces int Reorient2DBy3D (TIDSortedElemSet & theFaces, TIDSortedElemSet & theVolumes, diff --git a/src/SMESHFiltersSelection/SMESH_Type.h b/src/SMESHFiltersSelection/SMESH_Type.h index 5aa2df226..2d2838c12 100644 --- a/src/SMESHFiltersSelection/SMESH_Type.h +++ b/src/SMESHFiltersSelection/SMESH_Type.h @@ -62,7 +62,8 @@ namespace SMESH { IDSOURCE, IDSOURCE_EDGE, // IDSource including edges IDSOURCE_FACE, - IDSOURCE_VOLUME + IDSOURCE_VOLUME, + NB_SMESH_TYPES }; } #endif diff --git a/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx b/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx index d7b0b4f88..e5c74545a 100644 --- a/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx @@ -81,8 +81,6 @@ #include // IDL includes -#include -#include CORBA_SERVER_HEADER(SMESH_Mesh) #include CORBA_SERVER_HEADER(SMESH_MeshEditor) // std @@ -91,8 +89,8 @@ #define SPACING 6 #define MARGIN 11 -enum { CONSTRUCTOR_POINT=0, CONSTRUCTOR_FACE, CONSTRUCTOR_VOLUME, - EObject, EPoint, EFace, EDirection, EVolumes }; +enum { CONSTRUCTOR_POINT=0, CONSTRUCTOR_FACE, CONSTRUCTOR_FACE_GROUPS, CONSTRUCTOR_VOLUME, + EObject, EPoint, EFace, EDirection, ERefGroups }; //======================================================================= /*! @@ -130,6 +128,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 iconReoriGroups(resMgr()->loadPixmap("SMESH", tr("ICON_DLG_REORIENT2D_GROUPS"))); QPixmap iconReoriVolum (resMgr()->loadPixmap("SMESH", tr("ICON_DLG_REORIENT2D_VOLUME"))); QGroupBox* aConstructorBox = new QGroupBox(tr("REORIENT_FACES"), aFrame); @@ -149,6 +148,11 @@ QWidget* SMESHGUI_ReorientFacesDlg::createMainFrame (QWidget* theParent) aConstructorGrpLayout->addWidget(aFaceBut); myConstructorGrp->addButton(aFaceBut, CONSTRUCTOR_FACE); + QRadioButton* aGroupBut= new QRadioButton(aConstructorBox); + aGroupBut->setIcon(iconReoriGroups); + aConstructorGrpLayout->addWidget(aGroupBut); + myConstructorGrp->addButton(aGroupBut, CONSTRUCTOR_FACE_GROUPS); + QRadioButton* aVolBut= new QRadioButton(aConstructorBox); aVolBut->setIcon(iconReoriVolum); aConstructorGrpLayout->addWidget(aVolBut); @@ -162,9 +166,10 @@ 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 ); + createObject( tr("VOLUMES"), aFrame, ERefGroups ); + setNameIndication( EObject, ListOfNames ); setNameIndication( EFace, OneName ); + setNameIndication( ERefGroups, ListOfNames ); setReadOnly( EFace, false ); if ( QLineEdit* le = qobject_cast( objectWg( EFace, Control ) )) le->setValidator( new SMESHGUI_IdValidator( this,1 )); @@ -174,7 +179,6 @@ QWidget* SMESHGUI_ReorientFacesDlg::createMainFrame (QWidget* theParent) 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 ); @@ -246,14 +250,14 @@ QWidget* SMESHGUI_ReorientFacesDlg::createMainFrame (QWidget* theParent) aFaceGrpLayout->addWidget( objectWg( EFace, Btn ) ); aFaceGrpLayout->addWidget( objectWg( EFace, Control ) ); - 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 ); + myRefGroupFrm = new QFrame(aFrame); + QGridLayout* aRefGrpLayout = new QGridLayout(myRefGroupFrm); + aRefGrpLayout->setMargin(0); + aRefGrpLayout->setSpacing(SPACING); + aRefGrpLayout->addWidget( objectWg( ERefGroups, Label ), 0, 0 ); + aRefGrpLayout->addWidget( objectWg( ERefGroups, Btn ), 0, 1 ); + aRefGrpLayout->addWidget( objectWg( ERefGroups, Control ), 0, 2 ); + aRefGrpLayout->addWidget( myOutsideChk, 1, 0, 1, 3 ); myDirFrm = new QFrame(aFrame); QHBoxLayout* aDirectGrpLayout = new QHBoxLayout(myDirFrm); @@ -273,7 +277,7 @@ QWidget* SMESHGUI_ReorientFacesDlg::createMainFrame (QWidget* theParent) QVBoxLayout* anOrientGrpLayout = new QVBoxLayout ( anOrientGrp ); anOrientGrpLayout->addWidget(myPointFrm); anOrientGrpLayout->addWidget(myFaceFrm); - anOrientGrpLayout->addWidget(myVolumFrm); + anOrientGrpLayout->addWidget(myRefGroupFrm); anOrientGrpLayout->addWidget(myDirFrm); @@ -298,7 +302,7 @@ void SMESHGUI_ReorientFacesDlg::constructorChange(int id) if ( id == CONSTRUCTOR_FACE ) { myPointFrm->hide(); - myVolumFrm->hide(); + myRefGroupFrm->hide(); myFaceFrm->show(); myDirFrm->show(); activateObject( EFace ); @@ -306,25 +310,57 @@ void SMESHGUI_ReorientFacesDlg::constructorChange(int id) else if ( id == CONSTRUCTOR_POINT ) { myFaceFrm->hide(); - myVolumFrm->hide(); + myRefGroupFrm->hide(); myPointFrm->show(); myDirFrm->show(); activateObject( EPoint ); } - else // CONSTRUCTOR_VOLUME + else // CONSTRUCTOR_VOLUME || CONSTRUCTOR_FACE_GROUPS { myFaceFrm->hide(); myPointFrm->hide(); myDirFrm->hide(); - myVolumFrm->show(); - activateObject( EVolumes ); + myOutsideChk->setVisible( id == CONSTRUCTOR_VOLUME ); + myRefGroupFrm->show(); + QAbstractButton* refButton = qobject_cast( objectWg( ERefGroups, Btn )); + refButton->setChecked( false ); // force ERefGroups activation + activateObject( ERefGroups ); + setLabel( ERefGroups, id == CONSTRUCTOR_VOLUME ? "VOLUMES" : "REF_GROUPS" ); + } + + // minimize width of labels + QFontMetrics font = objectWg( EDirection, Label )->fontMetrics(); + int width = 0; + for ( int obj = EObject; obj <= ERefGroups; ++obj ) + { + QLabel* label = qobject_cast< QLabel* >( objectWg( obj, Label )); + if ( label->isVisible() ) + width = std::max( width, font.width( label->text() )); + } + + for ( int obj = EObject; obj <= ERefGroups; ++obj ) + { + QWidget* label = objectWg( obj, Label ); + if ( label->isVisible() ) + label->setFixedWidth( width ); } } +//================================================================================ +/*! + * \brief Set object label + */ +//================================================================================ + +void SMESHGUI_ReorientFacesDlg::setLabel( int object, const char* text ) +{ + qobject_cast< QLabel* >( objectWg( object, Label ))->setText( tr( text )); +} + //================================================================================ /*! * \brief Constructor -*/ + */ //================================================================================ SMESHGUI_ReorientFacesOp::SMESHGUI_ReorientFacesOp() @@ -336,16 +372,16 @@ SMESHGUI_ReorientFacesOp::SMESHGUI_ReorientFacesOp() myDlg = new SMESHGUI_ReorientFacesDlg; myDlg->constructorChange( CONSTRUCTOR_POINT ); + myRefGroupFilter = new SMESH_TypeFilter( SMESH::GROUP_VOLUME ); + myRefSubMeshFilter = new SMESH_TypeFilter( SMESH::SUBMESH_SOLID ); + myRefMeshFilter = new SMESH_TypeFilter( SMESH::MESH ); + + myObjects = new SMESH::ListOfIDSources(); + myRefGroups = new SMESH::ListOfIDSources(); + // connect signals and slots connect( myDlg->objectWg( EFace, LightApp_Dialog::Control ), SIGNAL(textChanged(const QString&)), this, SLOT(onTextChange(const QString&))); - // connect(myDlg->myX, SIGNAL (valueChanged(double)), this, SLOT(redisplayPreview())); - // connect(myDlg->myY, SIGNAL (valueChanged(double)), this, SLOT(redisplayPreview())); - // connect(myDlg->myZ, SIGNAL (valueChanged(double)), this, SLOT(redisplayPreview())); - // connect(myDlg->myDX, SIGNAL (valueChanged(double)), this, SLOT(redisplayPreview())); - // connect(myDlg->myDY, SIGNAL (valueChanged(double)), this, SLOT(redisplayPreview())); - // connect(myDlg->myDZ, SIGNAL (valueChanged(double)), this, SLOT(redisplayPreview())); - } //======================================================================= @@ -357,23 +393,14 @@ void SMESHGUI_ReorientFacesOp::startOperation() { myObjectActor = 0; - // init simulation with a current View - //if ( myVectorPreview ) delete myVectorPreview; - // myVectorPreview = new SMESHGUI_MeshEditPreview(SMESH::GetViewWindow( getSMESHGUI() )); - // vtkProperty* aProp = vtkProperty::New(); - // aProp->SetRepresentationToWireframe(); - // aProp->SetColor(250, 0, 250); - // aProp->SetPointSize(5); - // aProp->SetLineWidth( SMESH::GetFloat("SMESH:element_width",1) + 1); - // myVectorPreview->GetActor()->SetProperty(aProp); - // aProp->Delete(); - SMESHGUI_SelectionOp::startOperation(); myDlg->show(); - mySelectionMode = 0; + mySelectionMode = EObject; myDlg->activateObject( EObject ); + + selectionDone(); } //================================================================================ @@ -384,8 +411,8 @@ void SMESHGUI_ReorientFacesOp::startOperation() void SMESHGUI_ReorientFacesOp::stopOperation() { - //myVectorPreview->SetVisibility(false); - if ( myObjectActor ) { + if ( myObjectActor ) + { myObjectActor->SetPointRepresentation(false); SMESH::RepaintCurrentView(); myObjectActor = 0; @@ -403,31 +430,43 @@ void SMESHGUI_ReorientFacesOp::stopOperation() void SMESHGUI_ReorientFacesOp::onActivateObject( int what ) { if ( what == mySelectionMode ) - return; - mySelectionMode = what; - switch ( mySelectionMode ) { - case EPoint: - case EDirection: - SMESH::SetPointRepresentation(true); - setSelectionMode( NodeSelection ); - SMESH::SetPickable(); - break; - case EObject: - case EVolumes: - SMESH::SetPointRepresentation(false); - setSelectionMode( ActorSelection ); - break; - case EFace: - SMESH::SetPointRepresentation(false); - setSelectionMode( FaceSelection ); - if ( myObjectActor ) - SMESH::SetPickable( myObjectActor ); - else + if ( what == ERefGroups ) + setRefFiltersByConstructor(); + } + else + { + mySelectionMode = what; + switch ( mySelectionMode ) + { + case EPoint: + case EDirection: + SMESH::SetPointRepresentation(true); + setSelectionMode( NodeSelection ); SMESH::SetPickable(); - break; + break; + case EObject: + SMESH::SetPointRepresentation(false); + setSelectionMode( ActorSelection ); + break; + case ERefGroups: + SMESH::SetPointRepresentation(false); + setSelectionMode( ActorSelection ); + setRefFiltersByConstructor(); + break; + case EFace: + SMESH::SetPointRepresentation(false); + setSelectionMode( FaceSelection ); + if ( myObjectActor ) + SMESH::SetPickable( myObjectActor ); + else + SMESH::SetPickable(); + break; + } } SMESHGUI_SelectionOp::onActivateObject( what ); + + myDlg->setLabel( EObject, onlyOneObjAllowed() ? "OBJECT" : "OBJECTS" ); } //================================================================================ @@ -448,12 +487,10 @@ 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: + case ERefGroups: { 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 )); + filters << myRefGroupFilter << myRefSubMeshFilter << myRefMeshFilter; return new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR ); } case EPoint: @@ -472,6 +509,28 @@ SUIT_SelectionFilter* SMESHGUI_ReorientFacesOp::createFilter( const int what ) c return NULL; } +//================================================================================ +/*! + * \brief Switch between selection of faces and volumes according to the constructor + */ +//================================================================================ + +void SMESHGUI_ReorientFacesOp::setRefFiltersByConstructor() +{ + if ( constructorID() == CONSTRUCTOR_VOLUME ) + { + myRefMeshFilter ->setType( SMESH::MESH );// SMESH::NB_SMESH_TYPES + myRefGroupFilter ->setType( SMESH::GROUP_VOLUME ); + myRefSubMeshFilter->setType( SMESH::SUBMESH_SOLID ); + } + else + { + myRefMeshFilter ->setType( SMESH::NB_SMESH_TYPES ); // mesh not allowed + myRefGroupFilter ->setType( SMESH::GROUP_FACE ); + myRefSubMeshFilter->setType( SMESH::SUBMESH_FACE ); + } +} + //================================================================================ /*! * \brief get data from selection @@ -483,12 +542,6 @@ void SMESHGUI_ReorientFacesOp::selectionDone() if ( !myDlg->isVisible() || !myDlg->isEnabled() ) return; - if ( mySelectionMode == EVolumes ) - { - SMESHGUI_SelectionOp::selectionDone(); - return; - } - myDlg->clearSelection( mySelectionMode ); SALOME_ListIO aList; @@ -497,6 +550,15 @@ void SMESHGUI_ReorientFacesOp::selectionDone() if ( nbSelected == 0 ) return; + if ( onlyOneObjAllowed() && nbSelected != 1 ) + return; + + if ( mySelectionMode == ERefGroups ) + { + SMESHGUI_SelectionOp::selectionDone(); + return; + } + Handle(SALOME_InteractiveObject) anIO = aList.First(); try @@ -505,35 +567,27 @@ void SMESHGUI_ReorientFacesOp::selectionDone() { case EObject: { // get an actor of object - if ( nbSelected == 1 ) - { - myDlg->selectObject( EObject, anIO->getName(), 0, anIO->getEntry(), true ); - // typeById( aList.First()->getEntry(), - // SMESHGUI_SelectionOp::Object ), - myObjectActor = SMESH::FindActorByEntry( anIO->getEntry() ); - } + SMESHGUI_SelectionOp::selectionDone(); + myObjectActor = SMESH::FindActorByEntry( anIO->getEntry() ); break; } case EFace: { // get a face ID - if ( nbSelected == 1 ) + SVTK_TIndexedMapOfVtkId faceIndices; + selector()->GetIndex( anIO, faceIndices ); + if ( faceIndices.Extent() == 1 ) { - SVTK_TIndexedMapOfVtkId faceIndices; - selector()->GetIndex( anIO, faceIndices ); - if ( faceIndices.Extent() == 1 ) - { - SMESH_Actor* savedActor = myObjectActor; - myObjectActor = 0; // to prevent work of onTextChange() - myDlg->setObjectText( EFace, QString("%1").arg( faceIndices(1) )); - myObjectActor = savedActor; + SMESH_Actor* savedActor = myObjectActor; + myObjectActor = 0; // to prevent work of onTextChange() + myDlg->setObjectText( EFace, QString("%1").arg( faceIndices(1) )); + myObjectActor = savedActor; - if ( !myObjectActor ) - { - myDlg->selectObject( EObject, anIO->getName(), 0, anIO->getEntry(), true ); - // typeById( aList.First()->getEntry(), - // SMESHGUI_SelectionOp::Object ), - myObjectActor = SMESH::FindActorByEntry( anIO->getEntry() ); - } + if ( !myObjectActor ) + { + myDlg->selectObject( EObject, anIO->getName(), 0, anIO->getEntry(), true ); + // typeById( aList.First()->getEntry(), + // SMESHGUI_SelectionOp::Object ), + myObjectActor = SMESH::FindActorByEntry( anIO->getEntry() ); } } break; @@ -541,9 +595,6 @@ void SMESHGUI_ReorientFacesOp::selectionDone() case EPoint: case EDirection: { // set XYZ by selected nodes or vertices - if ( mySelectionMode == EPoint && aList.Extent() > 1 ) - return; - TColgp_SequenceOfXYZ points; for( SALOME_ListIteratorOfListIO anIt( aList ); anIt.More(); anIt.Next() ) { @@ -660,24 +711,30 @@ bool SMESHGUI_ReorientFacesOp::onApply() try { SUIT_OverrideCursor wc; - SMESH::SMESH_Mesh_var aMesh = myObject->GetMesh(); + SMESH::SMESH_Mesh_var aMesh = myObjects[0]->GetMesh(); if ( aMesh->_is_nil() ) return false; SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor(); if (aMeshEditor->_is_nil()) return false; int aResult = 0; - if ( myDlg->myConstructorGrp->checkedId() == CONSTRUCTOR_VOLUME ) + switch ( constructorID() ) + { + case 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 ); + aResult = aMeshEditor->Reorient2DBy3D( myObjects, myRefGroups[0], outsideNormal ); + + break; } - else + case CONSTRUCTOR_FACE_GROUPS: + { + aResult = aMeshEditor->Reorient2DByNeighbours( myObjects, myRefGroups ); + + break; + } + default: { SMESH::DirStruct direction; direction.PS.x = myDlg->myDX->GetValue(); @@ -685,7 +742,7 @@ bool SMESHGUI_ReorientFacesOp::onApply() direction.PS.z = myDlg->myDZ->GetValue(); long face = myDlg->objectText( EFace ).toInt(); - if ( myDlg->myConstructorGrp->checkedId() == CONSTRUCTOR_POINT ) + if ( constructorID() == CONSTRUCTOR_POINT ) face = -1; SMESH::PointStruct point; @@ -695,7 +752,8 @@ bool SMESHGUI_ReorientFacesOp::onApply() aMesh->SetParameters( aParameters.join(":").toUtf8().constData() ); - aResult = aMeshEditor->Reorient2D( myObject, direction, face, point ); + aResult = aMeshEditor->Reorient2D( myObjects[0], direction, face, point ); + } } if (aResult) @@ -726,47 +784,71 @@ bool SMESHGUI_ReorientFacesOp::onApply() bool SMESHGUI_ReorientFacesOp::isValid( QString& msg ) { - // check object - QString objectEntry = myDlg->selectedObject( EObject ); - _PTR(SObject) pSObject = SMESH::getStudy()->FindObjectID( objectEntry.toUtf8().data() ); - myObject = SMESH::SMESH_IDSource::_narrow( _CAST( SObject,pSObject )->GetObject() ); - if ( myObject->_is_nil() ) + // Check objects + + QStringList objectEntries; + myDlg->selectedObject( EObject, objectEntries ); + if ( objectEntries.size() == 0 ) { msg = tr("NO_OBJECT_SELECTED"); return false; } - bool hasFaces = false; - SMESH::array_of_ElementType_var types = myObject->GetTypes(); - for ( size_t i = 0; i < types->length() && !hasFaces; ++i ) - hasFaces = ( types[i] == SMESH::FACE ); - if ( !hasFaces ) + myObjects->length( objectEntries.size() ); + int nbObj = 0; + for ( QString & entry : objectEntries ) + { + SMESH::SMESH_IDSource_var obj = SMESH::EntryToInterface< SMESH::SMESH_IDSource >( entry ); + if ( !obj->_is_nil() ) + { + bool hasFaces = false; + SMESH::array_of_ElementType_var types = obj->GetTypes(); + for ( size_t i = 0; i < types->length() && !hasFaces; ++i ) + hasFaces = ( types[i] == SMESH::FACE ); + if ( hasFaces ) + myObjects[ nbObj++ ] = SMESH::SMESH_IDSource::_duplicate( obj ); + } + } + if ( nbObj == 0 ) { msg = tr("NO_FACES"); return false; } + myObjects->length( nbObj ); - // check volume object - if ( myDlg->myConstructorGrp->checkedId() == CONSTRUCTOR_VOLUME ) + // Check volume object or ref faces + + int constructorType = constructorID(); + if ( constructorType >= CONSTRUCTOR_FACE_GROUPS ) { - objectEntry = myDlg->selectedObject( EVolumes ); - _PTR(SObject) pSObject = SMESH::getStudy()->FindObjectID( objectEntry.toUtf8().data() ); - myVolumeObj = SMESH::SObjectToInterface< SMESH::SMESH_IDSource>( pSObject ); - if ( myVolumeObj->_is_nil() ) + objectEntries.clear(); + myDlg->selectedObject( ERefGroups, objectEntries ); + myRefGroups->length( objectEntries.size() ); + nbObj = 0; + for ( QString & entry : objectEntries ) { - msg = tr("NO_VOLUME_OBJECT_SELECTED"); - return false; + SMESH::SMESH_IDSource_var obj = SMESH::EntryToInterface< SMESH::SMESH_IDSource >( entry ); + if ( !obj->_is_nil() ) + { + bool hasElems = false; + SMESH::ElementType elemType = + ( constructorType == CONSTRUCTOR_VOLUME ? SMESH::VOLUME : SMESH::FACE ); + SMESH::array_of_ElementType_var types = obj->GetTypes(); + for ( size_t i = 0; i < types->length() && !hasElems; ++i ) + hasElems = ( types[i] == elemType ); + if ( hasElems ) + myRefGroups[ nbObj++ ] = SMESH::SMESH_IDSource::_duplicate( obj ); + } } - bool hasVolumes = false; - types = myVolumeObj->GetTypes(); - for ( size_t i = 0; i < types->length() && !hasVolumes; ++i ) - hasVolumes = ( types[i] == SMESH::VOLUME ); - if ( !hasVolumes ) + if ( nbObj == 0 && constructorType == CONSTRUCTOR_VOLUME ) { msg = tr("NO_VOLUMES"); return false; } + myRefGroups->length( nbObj ); } - // check vector + + // Check vector + gp_Vec vec( myDlg->myDX->GetValue(), myDlg->myDY->GetValue(), myDlg->myDZ->GetValue() ); @@ -776,8 +858,9 @@ bool SMESHGUI_ReorientFacesOp::isValid( QString& msg ) return false; } - // check face ID - if ( myDlg->myConstructorGrp->checkedId() == CONSTRUCTOR_FACE ) + // Check face ID + + if ( constructorID() == CONSTRUCTOR_FACE ) { int faceID = myDlg->objectText( EFace ).toInt(); bool faceOK = ( faceID > 0 ); @@ -789,8 +872,8 @@ bool SMESHGUI_ReorientFacesOp::isValid( QString& msg ) } else { - SMESH::SMESH_Mesh_var aMesh = myObject->GetMesh(); - if ( !aMesh->_is_nil() ) + SMESH::SMESH_Mesh_var aMesh = myObjects[0]->GetMesh(); + if ( !aMesh->_is_nil() ) faceOK = ( aMesh->GetElementType( faceID, true ) == SMESH::FACE ); } } @@ -807,7 +890,7 @@ bool SMESHGUI_ReorientFacesOp::isValid( QString& msg ) //================================================================================ /*! * \brief Destructor -*/ + */ //================================================================================ SMESHGUI_ReorientFacesOp::~SMESHGUI_ReorientFacesOp() @@ -828,6 +911,29 @@ LightApp_Dialog* SMESHGUI_ReorientFacesOp::dlg() const return myDlg; } +//================================================================================ +/*! + * \brief ID of a current constructor: CONSTRUCTOR_FACE, CONSTRUCTOR_POINT etc. + */ +//================================================================================ + +int SMESHGUI_ReorientFacesOp::constructorID() +{ + return myDlg->myConstructorGrp->checkedId(); +} + +//================================================================================ +/*! + * \brief Check if selection of multiple objects allowed + */ +//================================================================================ + +bool SMESHGUI_ReorientFacesOp::onlyOneObjAllowed() +{ + return (( constructorID() <= CONSTRUCTOR_FACE ) || + ( constructorID() == CONSTRUCTOR_VOLUME && mySelectionMode == ERefGroups )); +} + //================================================================================ /*! * \brief update preview @@ -836,110 +942,4 @@ LightApp_Dialog* SMESHGUI_ReorientFacesOp::dlg() const void SMESHGUI_ReorientFacesOp::redisplayPreview() { -// SMESH::MeshPreviewStruct_var aMeshPreviewStruct; - -// bool moveShown = false; -// if ( myObjectActor) -// { -// const bool autoSearch = myDlg->myAutoSearchChkBox->isChecked(); -// const bool preview = myDlg->myPreviewChkBox->isChecked(); -// if ( autoSearch ) -// { -// myDlg->myCurrentX->SetValue(0); -// myDlg->myCurrentY->SetValue(0); -// myDlg->myCurrentZ->SetValue(0); -// myDlg->myDX->SetValue(0); -// myDlg->myDY->SetValue(0); -// myDlg->myDZ->SetValue(0); -// myDlg->myId->setText(""); -// } -// QString msg; -// if ( autoSearch || isValid( msg ) ) -// { -// try { -// SMESH::SMESH_Mesh_var aMesh = SMESH::GetMeshByIO(myObjectActor->getIO()); -// if (!aMesh->_is_nil()) { -// SMESH::SMESH_MeshEditor_var aPreviewer = aMesh->GetMeshEditPreviewer(); -// if (!aPreviewer->_is_nil()) -// { -// SUIT_OverrideCursor aWaitCursor; - -// int anId = 0; -// if ( autoSearch ) -// anId = aPreviewer->FindNodeClosestTo(myDlg->myX->GetValue(), -// myDlg->myY->GetValue(), -// myDlg->myZ->GetValue()); -// else -// anId = myDlg->myId->text().toInt(); - -// // find id and/or just compute preview -// aPreviewer->MoveNode(anId, -// myDlg->myX->GetValue(), -// myDlg->myY->GetValue(), -// myDlg->myZ->GetValue()); -// if ( autoSearch ) { // set found id -// QString idTxt("%1"); -// if ( anId > 0 ) -// idTxt = idTxt.arg( anId ); -// else -// idTxt = ""; -// myDlg->myId->setText( idTxt ); -// } - -// SMESH::double_array* aXYZ = aMesh->GetNodeXYZ( anId ); -// if( aXYZ && aXYZ->length() >= 3 ) -// { -// double x = aXYZ->operator[](0); -// double y = aXYZ->operator[](1); -// double z = aXYZ->operator[](2); -// double dx = myDlg->myX->GetValue() - x; -// double dy = myDlg->myY->GetValue() - y; -// double dz = myDlg->myZ->GetValue() - z; -// myDlg->myCurrentX->SetValue(x); -// myDlg->myCurrentY->SetValue(y); -// myDlg->myCurrentZ->SetValue(z); -// myDlg->myDX->SetValue(dx); -// myDlg->myDY->SetValue(dy); -// myDlg->myDZ->SetValue(dz); -// } - -// if ( preview ) { // fill preview data -// aMeshPreviewStruct = aPreviewer->GetPreviewData(); -// moveShown = ( anId > 0 ); -// } -// } -// } -// }catch (...) { -// } -// } -// } - -// if ( !moveShown ) -// { -// aMeshPreviewStruct = new SMESH::MeshPreviewStruct(); - -// aMeshPreviewStruct->nodesXYZ.length(1); -// aMeshPreviewStruct->nodesXYZ[0].x = myDlg->myX->GetValue(); -// aMeshPreviewStruct->nodesXYZ[0].y = myDlg->myY->GetValue(); -// aMeshPreviewStruct->nodesXYZ[0].z = myDlg->myZ->GetValue(); - -// aMeshPreviewStruct->elementTypes.length(1); -// aMeshPreviewStruct->elementTypes[0].SMDS_ElementType = SMESH::NODE; -// aMeshPreviewStruct->elementTypes[0].isPoly = false; -// aMeshPreviewStruct->elementTypes[0].nbNodesInElement = 1; - -// aMeshPreviewStruct->elementConnectivities.length(1); -// aMeshPreviewStruct->elementConnectivities[0] = 0; -// } - -// // display data -// if ( & aMeshPreviewStruct.in() ) -// { -// myVectorPreview->SetData(aMeshPreviewStruct.in()); -// } -// else -// { -// myVectorPreview->SetVisibility(false); -// } - } diff --git a/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.h b/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.h index e9df0563a..5b86db6ff 100644 --- a/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.h +++ b/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.h @@ -27,31 +27,37 @@ #define SMESHGUI_ReorientFacesDlg_H // SMESH includes + #include "SMESH_SMESHGUI.hxx" #include "SMESHGUI_Dialog.h" #include "SMESHGUI_SelectionOp.h" +#include +#include CORBA_SERVER_HEADER(SMESH_Mesh) + class QButtonGroup; class QCheckBox; class QLineEdit; class SMESHGUI_SpinBox; class SMESHGUI_ReorientFacesDlg; +class SMESH_TypeFilter; -/*! +/*! ================================================================================ * \brief Operation to reorient faces according to some criterion */ + class SMESHGUI_EXPORT SMESHGUI_ReorientFacesOp: public SMESHGUI_SelectionOp { Q_OBJECT -public: + public: SMESHGUI_ReorientFacesOp(); virtual ~SMESHGUI_ReorientFacesOp(); virtual LightApp_Dialog* dlg() const; -protected: + protected: virtual void startOperation(); virtual void stopOperation(); @@ -60,27 +66,35 @@ protected: virtual void selectionDone(); bool isValid( QString& ); + void setRefFiltersByConstructor(); + int constructorID(); -protected slots: + + protected slots: virtual bool onApply(); -private slots: + private slots: virtual void onActivateObject( int ); void redisplayPreview(); void onTextChange( const QString& ); + bool onlyOneObjAllowed(); -private: - SMESHGUI_ReorientFacesDlg* myDlg; + private: - //SMESHGUI_MeshEditPreview* myVectorPreview; - SMESH_Actor* myObjectActor; - int mySelectionMode; + SMESHGUI_ReorientFacesDlg* myDlg; - SMESH::SMESH_IDSource_var myObject; - SMESH::SMESH_IDSource_var myVolumeObj; + SMESH_Actor* myObjectActor; + int mySelectionMode; + + SMESH_TypeFilter* myRefGroupFilter; + SMESH_TypeFilter* myRefSubMeshFilter; + SMESH_TypeFilter* myRefMeshFilter; + + SMESH::ListOfIDSources_var myObjects; + SMESH::ListOfIDSources_var myRefGroups; }; -/*! +/*! ================================================================================ * \brief Dialog to reorient faces according to vector */ @@ -88,7 +102,7 @@ class SMESHGUI_EXPORT SMESHGUI_ReorientFacesDlg : public SMESHGUI_Dialog { Q_OBJECT -public: + public: SMESHGUI_ReorientFacesDlg(); public slots: @@ -96,12 +110,13 @@ public slots: private: QWidget* createMainFrame( QWidget* ); + void setLabel( int object, const char* text ); QButtonGroup* myConstructorGrp; QFrame* myFaceFrm; QFrame* myPointFrm; QFrame* myDirFrm; - QFrame* myVolumFrm; + QFrame* myRefGroupFrm; QCheckBox* myOutsideChk; SMESHGUI_SpinBox* myX; SMESHGUI_SpinBox* myY; diff --git a/src/SMESHGUI/SMESH_images.ts b/src/SMESHGUI/SMESH_images.ts index 317a769cb..74697d463 100644 --- a/src/SMESHGUI/SMESH_images.ts +++ b/src/SMESHGUI/SMESH_images.ts @@ -495,6 +495,10 @@ ICON_DLG_REORIENT2D_FACE reorient_faces_face.png + + ICON_DLG_REORIENT2D_GROUPS + reorient_faces_ref_groups.png + ICON_DLG_REORIENT2D_VOLUME reorient_faces_volume.png diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index 8c4e75870..67ca49fe5 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -8609,6 +8609,10 @@ red in the Object Browser. OBJECT Object + + OBJECTS + Objects + POINT Point @@ -8629,6 +8633,10 @@ red in the Object Browser. VOLUMES Volumes + + REF_GROUPS + Ref. objects (optional) + OUTSIDE_VOLUME_NORMAL Face normal outside volume diff --git a/src/SMESHGUI/SMESH_msg_fr.ts b/src/SMESHGUI/SMESH_msg_fr.ts index a91b39971..5ff731606 100644 --- a/src/SMESHGUI/SMESH_msg_fr.ts +++ b/src/SMESHGUI/SMESH_msg_fr.ts @@ -674,15 +674,15 @@ TOP_REORIENT_2D - Réorienter des faces selon un vecteur + Réorienter des faces MEN_REORIENT_2D - Réorienter des faces selon un vecteur + Réorienter des faces STB_REORIENT_2D - Réorienter des faces selon un vecteur + Réorienter des faces TOP_FIND_ELEM @@ -8613,7 +8613,7 @@ en rouge dans le browser. SMESHGUI_ReorientFacesDlg CAPTION - Réorienter des faces selon un vector + Réorienter des faces REORIENT_FACES @@ -8627,6 +8627,10 @@ en rouge dans le browser. OBJECT Objet + + OBJECTS + Objets + POINT Point @@ -8647,6 +8651,10 @@ en rouge dans le browser. VOLUMES Volumes + + REF_GROUPS + Objets de référence (optionnel) + OUTSIDE_VOLUME_NORMAL Normale de face en dehors du volume diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index 5f3456bb9..07b3d3399 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -2489,8 +2489,8 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand) "RemoveElements","RemoveNodes","RemoveOrphanNodes", "AddNode","Add0DElement","AddEdge","AddFace","AddPolygonalFace","AddBall", "AddVolume","AddPolyhedralVolume","AddPolyhedralVolumeByFaces", - "MoveNode", "MoveClosestNodeToPoint", - "InverseDiag","DeleteDiag","Reorient","ReorientObject","Reorient2DBy3D", + "MoveNode", "MoveClosestNodeToPoint","InverseDiag","DeleteDiag", + "Reorient","ReorientObject","Reorient2DBy3D","Reorient2DByNeighbours", "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 f11615845..323a6603a 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -1696,7 +1696,8 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup, if ( dirVec.Magnitude() < std::numeric_limits< double >::min() ) THROW_SALOME_CORBA_EXCEPTION("Zero size vector", SALOME::BAD_PARAM); - int nbReori = getEditor().Reorient2D( elements, dirVec, face ); + TIDSortedElemSet refFaces = { face }; + int nbReori = getEditor().Reorient2D( elements, dirVec, refFaces, /*allowNonManifold=*/true ); if ( nbReori ) { declareMeshModified( /*isReComputeSafe=*/false ); @@ -1713,6 +1714,64 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup, return 0; } +//======================================================================= +//function : Reorient2DByNeighbours +//purpose : Reorient faces contained in a list of objectFaces +// equally to faces contained in a list of referenceFaces. +//======================================================================= + +CORBA::Long +SMESH_MeshEditor_i::Reorient2DByNeighbours(const SMESH::ListOfIDSources& theObjectFaces, + const SMESH::ListOfIDSources& theReferenceFaces) +{ + SMESH_TRY; + initData(/*deleteSearchers=*/false); + + if ( theObjectFaces.length() == 0 ) + return 0; + + // get object faces + TIDSortedElemSet objFaces; + bool invalidObjFaces = false; + for ( CORBA::ULong i = 0; i < theObjectFaces.length(); ++i ) + { + IDSource_Error err; + if ( !idSourceToSet( theObjectFaces[i], getMeshDS(), objFaces, SMDSAbs_Face, + /*emptyIfIsMesh=*/1, &err ) && + err == IDSource_INVALID ) + invalidObjFaces = true; + } + if ( objFaces.empty() && invalidObjFaces ) + THROW_SALOME_CORBA_EXCEPTION("No valid faces in given groups", SALOME::BAD_PARAM); + + // get reference faces + TIDSortedElemSet refFaces; + for ( CORBA::ULong i = 0; i < theReferenceFaces.length(); ++i ) + { + idSourceToSet( theReferenceFaces[i], getMeshDS(), refFaces, SMDSAbs_Face, /*emptyIfIsMesh=*/1 ); + } + if ( refFaces.empty() && theReferenceFaces.length() > 0 ) + THROW_SALOME_CORBA_EXCEPTION("Reference faces are invalid", SALOME::BAD_PARAM); + + + gp_Vec zeroVec( 0,0,0 ); + + // reorient + int nbReori = getEditor().Reorient2D( objFaces, zeroVec, refFaces, /*allowNonManifold=*/false ); + + if ( nbReori ) + declareMeshModified( /*isReComputeSafe=*/false ); + + TPythonDump() << this << ".Reorient2DByNeighbours(" + << theObjectFaces << ", " + << theReferenceFaces << ")"; + + return nbReori; + + SMESH_CATCH( SMESH::throwCorbaException ); + return 0; +} + //======================================================================= //function : Reorient2DBy3D //purpose : Reorient faces basing on orientation of adjacent volumes. diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx index 69f62d539..3d7072ed4 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.hxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx @@ -192,6 +192,17 @@ public: const SMESH::DirStruct& theDirection, CORBA::Long theFace, const SMESH::PointStruct& thePoint); + /*! + * \brief Reorient faces contained in a list of \a objectFaces + * equally to faces contained in a list of \a referenceFaces. + * \param objectFaces - faces to reorient in a list including either + * the whole mesh or groups and/or sub-meshes. + * \param referenceFaces - correctly oriented faces in a list of groups and/or sub-meshes. + * It can be empty, then the 1st face in \a objectFaces is used as the reference. + * \return number of reoriented faces. + */ + CORBA::Long Reorient2DByNeighbours(const SMESH::ListOfIDSources& objectFaces, + const SMESH::ListOfIDSources& referenceFaces); /*! * \brief Reorient faces basing on orientation of adjacent volumes. * \param faces - a list of objects containing face to reorient diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index 47744206c..1d5269c19 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -4664,6 +4664,29 @@ class Mesh(metaclass = MeshMeta): theFace = -1 return self.editor.Reorient2D( the2DObject, theDirection, theFace, thePoint ) + def Reorient2DByNeighbours(self, objectFaces, referenceFaces=[]): + """ + Reorient faces contained in a list of *objectFaces* + equally to faces contained in a list of *referenceFaces*. + + Parameters: + objectFaces: list of :class:`mesh, sub-mesh, group, filter ` holding faces to reorient. + referenceFaces: list of :class:`sub-mesh, group, filter ` holding reference faces. It can be empty, then any face in *objectFaces* is used as the reference. + + Returns: + number of reoriented faces. + """ + if not isinstance( objectFaces, list ): + objectFaces = [ objectFaces ] + for i,obj2D in enumerate( objectFaces ): + if isinstance( obj2D, Mesh ): + objectFaces[i] = obj2D.GetMesh() + if not isinstance( referenceFaces, list ): + referenceFaces = [ referenceFaces ] + + return self.editor.Reorient2DByNeighbours( objectFaces, referenceFaces ) + + def Reorient2DBy3D(self, the2DObject, the3DObject, theOutsideNormal=True ): """ Reorient faces according to adjacent volumes. diff --git a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx index dc82aa09a..c847d9efb 100644 --- a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx +++ b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx @@ -5644,8 +5644,8 @@ namespace continue; gp_Dir direction(1,0,0); - const SMDS_MeshElement* anyFace = *facesToOrient.begin(); - editor.Reorient2D( facesToOrient, direction, anyFace ); + TIDSortedElemSet refFaces; + editor.Reorient2D( facesToOrient, direction, refFaces, /*allowNonManifold=*/true ); } } return;