From 3d1337aceed97f14b26385a6143529197ab30f8d Mon Sep 17 00:00:00 2001 From: eap Date: Mon, 8 Nov 2021 19:38:38 +0300 Subject: [PATCH] bos #26452 [EDF] (2021) SMESH: orientation of faces --- .../examples/transforming_meshes_ex13.py | 17 + .../gui/SMESH/images/reorient_2d_refgroup.png | Bin 0 -> 20972 bytes .../gui/SMESH/images/reorient_faces_point.png | Bin 0 -> 839 bytes .../images/reorient_faces_ref_groups.png | Bin 0 -> 3320 bytes .../SMESH/images/reorient_faces_volume.png | Bin 0 -> 355 bytes doc/salome/gui/SMESH/input/modules.rst | 1 + doc/salome/gui/SMESH/input/reorient_faces.rst | 42 +- idl/SMESH_MeshEditor.idl | 14 + resources/CMakeLists.txt | 1 + resources/reorient_faces_ref_groups.png | Bin 0 -> 3320 bytes src/SMDS/SMDS_ElementFactory.cxx | 23 + src/SMDS/SMDS_ElementFactory.hxx | 3 + src/SMDS/SMDS_Mesh.cxx | 20 + src/SMDS/SMDS_Mesh.hxx | 3 + src/SMESH/SMESH_MeshEditor.cxx | 154 ++++-- src/SMESH/SMESH_MeshEditor.hxx | 11 +- src/SMESHFiltersSelection/SMESH_Type.h | 3 +- src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx | 490 +++++++++--------- src/SMESHGUI/SMESHGUI_ReorientFacesDlg.h | 45 +- src/SMESHGUI/SMESH_images.ts | 4 + src/SMESHGUI/SMESH_msg_en.ts | 8 + src/SMESH_I/SMESH_2smeshpy.cxx | 4 +- src/SMESH_I/SMESH_MeshEditor_i.cxx | 61 ++- src/SMESH_I/SMESH_MeshEditor_i.hxx | 11 + src/SMESH_SWIG/smeshBuilder.py | 23 + src/StdMeshers/StdMeshers_Cartesian_3D.cxx | 4 +- 26 files changed, 608 insertions(+), 334 deletions(-) create mode 100644 doc/salome/gui/SMESH/images/reorient_2d_refgroup.png create mode 100644 doc/salome/gui/SMESH/images/reorient_faces_point.png create mode 100644 doc/salome/gui/SMESH/images/reorient_faces_ref_groups.png create mode 100644 doc/salome/gui/SMESH/images/reorient_faces_volume.png create mode 100644 resources/reorient_faces_ref_groups.png 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 0000000000000000000000000000000000000000..f080f460b5738fad6f0c40ce0cd29c2896c437ce GIT binary patch literal 20972 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 a|79vee8Y^}7Qo{g89ZJ6T-G@yGywoPA_;T= literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..63fae723392f3be7d4803c0fc88aa0e4bed04d34 GIT binary patch literal 839 zcmV-N1GxN&P)Px#24YJ`L;z9%asZzDQYEPX000SaNLh0L01FZT01FZU(%pXi00007bV*G`2iyk& z2n8QcZOUf=00PHJL_t(I%Z-%FYZO5c#(y+AZes|#ZcD_TcKswM`ea_z91(bP02BI`t?X*pO#91#(qnovZR7~S1aUyteR z{0+oan8;xO1E+ztB0^R8wc<0ocbDf4Kr?{jIP-F?0ehE3Sc{Ox#`4?%9zfUNJp^0; zf%`xkfK*0i)37l5`}>X7ddhX(jrn|@AP6WH=O`2uVHlxxkuP6=v8%hAFbv6LGE$T9 z)VYhMcVGw%6z!Hcj)|2*#W6}L;wa?K#U8BJP9Wzlr}5ayGp6VG5RM4v_qPJ@;N>?8 zN}-|%6)B=9L`6~A?;UhPMDd zkgby3+qd5wz50yC#G-$#GLu1NA>jK(1yn1|=$%*U;khAVP9mmNAK@hqC z8`?LS8&5t^EI|=7pKzOeT`J)}*+ig)lYHMp78W5V$YZ*1NdRz^f6I8D RD;NL(002ovPDHLkV1h}DbN>JU literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f9cf53bd9beef0ea1376772f8dbbdcc9ef979f73 GIT binary patch literal 3320 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f9cf53bd9beef0ea1376772f8dbbdcc9ef979f73 GIT binary patch literal 3320 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 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 ( 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 ); - startFaces.insert( theFace ); + // 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..92aaeab16 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; + } + case CONSTRUCTOR_FACE_GROUPS: + { + aResult = aMeshEditor->ReOrient2DByNeighbours( myObjects, myRefGroups ); + + break; } - else + 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 or ref faces - // check volume object - if ( myDlg->myConstructorGrp->checkedId() == CONSTRUCTOR_VOLUME ) + 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_ReorientFacesDlg* myDlg; + + SMESH_Actor* myObjectActor; + int mySelectionMode; - //SMESHGUI_MeshEditPreview* myVectorPreview; - SMESH_Actor* myObjectActor; - int mySelectionMode; + SMESH_TypeFilter* myRefGroupFilter; + SMESH_TypeFilter* myRefSubMeshFilter; + SMESH_TypeFilter* myRefMeshFilter; - SMESH::SMESH_IDSource_var myObject; - SMESH::SMESH_IDSource_var myVolumeObj; + 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/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; -- 2.39.2