diff --git a/doc/salome/gui/SMESH/images/sew_after_merge.png b/doc/salome/gui/SMESH/images/sew_after_merge.png new file mode 100644 index 000000000..43d6869f7 Binary files /dev/null and b/doc/salome/gui/SMESH/images/sew_after_merge.png differ diff --git a/doc/salome/gui/SMESH/images/sew_using_merge.png b/doc/salome/gui/SMESH/images/sew_using_merge.png new file mode 100644 index 000000000..80cc44c67 Binary files /dev/null and b/doc/salome/gui/SMESH/images/sew_using_merge.png differ diff --git a/doc/salome/gui/SMESH/input/sewing_meshes.doc b/doc/salome/gui/SMESH/input/sewing_meshes.doc index ad5f15e65..b7640f30b 100644 --- a/doc/salome/gui/SMESH/input/sewing_meshes.doc +++ b/doc/salome/gui/SMESH/input/sewing_meshes.doc @@ -53,8 +53,12 @@ the opposite border. In practice the borders to sew often coincide and in this case it is difficult to specify the first and the last nodes of a border since they coincide with the first and the last nodes of the other -border. To cope with this, manually \ref merging_nodes_page to fuse -each pair of coincident nodes into one. +border. To cope with this, +\ref merging_nodes_page "merge" coincident nodes into one +beforehand. Two figures below illustrate this approach. +\image html sew_using_merge.png "Merge coincident nodes which are difficult to distinguish" +
+\image html sew_after_merge.png "After merging nodes it is easy to specify border nodes" The sewing algorithm is as follows:
    diff --git a/src/SMESHDS/SMESHDS_SubMesh.cxx b/src/SMESHDS/SMESHDS_SubMesh.cxx index f06ec6e31..04a0021fc 100644 --- a/src/SMESHDS/SMESHDS_SubMesh.cxx +++ b/src/SMESHDS/SMESHDS_SubMesh.cxx @@ -46,8 +46,6 @@ using namespace std; SMESHDS_SubMesh::SMESHDS_SubMesh(SMESHDS_Mesh *parent, int index) { myParent = parent; - myElements.clear(); - myNodes.clear(); myIndex = index; myUnusedIdNodes = 0; myUnusedIdElements = 0; @@ -65,61 +63,54 @@ SMESHDS_SubMesh::~SMESHDS_SubMesh() //======================================================================= //function : AddElement -//purpose : +//purpose : //======================================================================= void SMESHDS_SubMesh::AddElement(const SMDS_MeshElement * ME) { if (!IsComplexSubmesh()) + { + if ( ME->GetType() == SMDSAbs_Node ) { - if ( ME->GetType() == SMDSAbs_Node ) + AddNode( static_cast< const SMDS_MeshNode* >( ME )); + return; + } + int oldShapeId = ME->getshapeId(); + if ( oldShapeId > 0 ) + { + if (oldShapeId != myIndex) { - AddNode( static_cast< const SMDS_MeshNode* >( ME )); + throw SALOME_Exception + (LOCALIZED("add element in subshape already belonging to a subshape")); + } + int idInSubShape = ME->getIdInShape(); + if (idInSubShape >= 0) + { + MESSAGE("add element in subshape already belonging to that subshape " + << ME->GetID() << " " << oldShapeId << " " << idInSubShape); + // check if ok: do nothing if ok + if (idInSubShape >= myElements.size()) + { + throw SALOME_Exception(LOCALIZED("out of bounds")); + } + if (ME != myElements[idInSubShape]) + { + throw SALOME_Exception(LOCALIZED("not the same element")); + } return; } - int oldShapeId = ME->getshapeId(); - if ( oldShapeId > 0 ) - { - if (oldShapeId != myIndex) - { - MESSAGE("add element in subshape already belonging to another subshape " - << ME->GetID() << " " << oldShapeId << " " << myIndex); - throw SALOME_Exception(LOCALIZED("add element in subshape already belonging to a subshape")); - } - else - { - int idInSubShape = ME->getIdInShape(); - if (idInSubShape >= 0) - { - MESSAGE("add element in subshape already belonging to that subshape " - << ME->GetID() << " " << oldShapeId << " " << idInSubShape); - // check if ok: do nothing if ok - if (idInSubShape >= myElements.size()) - { - MESSAGE("out of bounds " << idInSubShape << " " << myElements.size()); - throw SALOME_Exception(LOCALIZED("out of bounds")); - } - if (ME != myElements[idInSubShape]) - { - MESSAGE("not the same element"); - throw SALOME_Exception(LOCALIZED("not the same element")); - } - MESSAGE("already done, OK, nothing to do"); - return; - } - } - } - - SMDS_MeshElement* elem = (SMDS_MeshElement*) (ME); - elem->setShapeId(myIndex); - elem->setIdInShape(myElements.size()); - myElements.push_back(ME); } + + SMDS_MeshElement* elem = (SMDS_MeshElement*) (ME); + elem->setShapeId(myIndex); + elem->setIdInShape(myElements.size()); + myElements.push_back(ME); + } } //======================================================================= //function : RemoveElement -//purpose : +//purpose : //======================================================================= bool SMESHDS_SubMesh::RemoveElement(const SMDS_MeshElement * ME, bool isElemDeleted) @@ -183,7 +174,7 @@ void SMESHDS_SubMesh::AddNode(const SMDS_MeshNode * N) //======================================================================= //function : RemoveNode -//purpose : +//purpose : //======================================================================= bool SMESHDS_SubMesh::RemoveNode(const SMDS_MeshNode * N, bool isNodeDeleted) @@ -385,29 +376,52 @@ bool SMESHDS_SubMesh::Contains(const SMDS_MeshElement * ME) const if (!ME) return false; - if (IsComplexSubmesh()) - { - set::const_iterator aSubIt = mySubMeshes.begin(); - for (; aSubIt != mySubMeshes.end(); aSubIt++) - if ((*aSubIt)->Contains(ME)) - return true; - return false; - } + if ( IsComplexSubmesh() ) + { + set::const_iterator aSubIt = mySubMeshes.begin(); + for (; aSubIt != mySubMeshes.end(); aSubIt++) + if ((*aSubIt)->Contains(ME)) + return true; + return false; + } if (ME->GetType() == SMDSAbs_Node) - { - int idInShape = ME->getIdInShape(); - if ((idInShape >= 0) && (idInShape < myNodes.size())) - if (myNodes[idInShape] == ME) - return true; - } + { + int idInShape = ME->getIdInShape(); + if ((idInShape >= 0) && (idInShape < myNodes.size())) + if (myNodes[idInShape] == ME) + return true; + } else - { - int idInShape = ME->getIdInShape(); - if ((idInShape >= 0) && (idInShape < myElements.size())) - if (myElements[idInShape] == ME) - return true; - } + { + int idInShape = ME->getIdInShape(); + if ((idInShape >= 0) && (idInShape < myElements.size())) + if (myElements[idInShape] == ME) + return true; + } + return false; +} + +//======================================================================= +//function : IsQuadratic +//purpose : Return true if my 1st element is quadratic +//======================================================================= + +bool SMESHDS_SubMesh::IsQuadratic() const +{ + if ( IsComplexSubmesh() ) + { + set::const_iterator aSubIt = mySubMeshes.begin(); + for (; aSubIt != mySubMeshes.end(); aSubIt++) + if ((*aSubIt)->IsQuadratic()) + return true; + return false; + } + + for ( size_t i = 0; i < myElements.size(); ++i ) + if ( myElements[i] ) + return myElements[i]->IsQuadratic(); + return false; } diff --git a/src/SMESHDS/SMESHDS_SubMesh.hxx b/src/SMESHDS/SMESHDS_SubMesh.hxx index 3460b8cdb..c70857c60 100644 --- a/src/SMESHDS/SMESHDS_SubMesh.hxx +++ b/src/SMESHDS/SMESHDS_SubMesh.hxx @@ -67,19 +67,20 @@ class SMESHDS_EXPORT SMESHDS_SubMesh virtual int NbNodes() const; virtual SMDS_NodeIteratorPtr GetNodes() const; virtual bool Contains(const SMDS_MeshElement * ME) const; // check if elem or node is in + virtual bool IsQuadratic() const; // clear the contents virtual void Clear(); - int getSize(); + int getSize(); void compactList(); SMESHDS_Mesh* GetParent() const { return const_cast< SMESHDS_Mesh*>( myParent ); } int GetID() const { return myIndex; } private: - SMESHDS_Mesh * myParent; + SMESHDS_Mesh * myParent; std::vector myElements; - std::vector myNodes; + std::vector myNodes; int myUnusedIdNodes; int myUnusedIdElements; diff --git a/src/SMESH_SWIG/smesh_algorithm.py b/src/SMESH_SWIG/smesh_algorithm.py index df027244b..9481ff1d7 100644 --- a/src/SMESH_SWIG/smesh_algorithm.py +++ b/src/SMESH_SWIG/smesh_algorithm.py @@ -287,8 +287,11 @@ class Mesh_Algorithm: if not "ViscousLayers" in self.GetCompatibleHypothesis(): raise TypeError, "ViscousLayers are not supported by %s"%self.algo.GetName() if faces and isinstance( faces[0], geomBuilder.GEOM._objref_GEOM_Object ): - import GEOM - faceIDs = [self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f) for f in faces] + faceIDs = [] + for shape in faces: + ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] ) + for f in ff: + faceIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f)) faces = faceIDs hyp = self.Hypothesis("ViscousLayers", [thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore], @@ -320,7 +323,12 @@ class Mesh_Algorithm: if not "ViscousLayers2D" in self.GetCompatibleHypothesis(): raise TypeError, "ViscousLayers2D are not supported by %s"%self.algo.GetName() if edges and isinstance( edges[0], geomBuilder.GEOM._objref_GEOM_Object ): - edges = [ self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f) for f in edges ] + edgeIDs = [] + for shape in edges: + ee = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"]) + for e in ee: + edgeIDs.append( self.mesh.geompyD.GetSubShapeID( self.mesh.geom, e )) + edges = edgeIDs hyp = self.Hypothesis("ViscousLayers2D", [thickness, numberOfLayers, stretchFactor, edges, isEdgesToIgnore], toAdd=False) diff --git a/src/StdMeshers/StdMeshers_FaceSide.cxx b/src/StdMeshers/StdMeshers_FaceSide.cxx index 377a79c5d..d1d20245d 100644 --- a/src/StdMeshers/StdMeshers_FaceSide.cxx +++ b/src/StdMeshers/StdMeshers_FaceSide.cxx @@ -311,7 +311,9 @@ const vector& StdMeshers_FaceSide::GetUVPtStruct(bool isXConst, StdMeshers_FaceSide* me = const_cast< StdMeshers_FaceSide* >( this ); SMESHDS_Mesh* meshDS = myProxyMesh->GetMeshDS(); - SMESH_MesherHelper helper( *myProxyMesh->GetMesh() ); + SMESH_MesherHelper eHelper( *myProxyMesh->GetMesh() ); + SMESH_MesherHelper fHelper( *myProxyMesh->GetMesh() ); + fHelper.SetSubShape( myFace ); bool paramOK; double eps = 1e-100; @@ -346,7 +348,8 @@ const vector& StdMeshers_FaceSide::GetUVPtStruct(bool isXConst, const double prevNormPar = ( iE == 0 ? 0 : myNormPar[ iE-1 ]); // normalized param if ( node ) // nodes on internal vertices may be missing { - if ( vertexNodes.insert( node ).second ) + if ( vertexNodes.insert( node ).second || + fHelper.IsRealSeam( node->getshapeId() )) u2node.insert( u2node.end(), make_pair( prevNormPar, node )); } else if ( iE == 0 ) @@ -373,12 +376,12 @@ const vector& StdMeshers_FaceSide::GetUVPtStruct(bool isXConst, u2nodeVec.clear(); double paramSize = myLast[iE] - myFirst[iE]; double r = myNormPar[iE] - prevNormPar; - helper.SetSubShape( myEdge[iE] ); - helper.ToFixNodeParameters( true ); + eHelper.SetSubShape( myEdge[iE] ); + eHelper.ToFixNodeParameters( true ); if ( !myIsUniform[iE] ) for ( size_t i = 0; i < nodes.size(); ++i ) { - double u = helper.GetNodeU( myEdge[iE], nodes[i], 0, ¶mOK ); + double u = eHelper.GetNodeU( myEdge[iE], nodes[i], 0, ¶mOK ); double aLenU = GCPnts_AbscissaPoint::Length( me->myC3dAdaptor[iE], myFirst[iE], u ); if ( myEdgeLength[iE] < aLenU ) // nonregression test "3D_mesh_NETGEN/G6" { @@ -391,7 +394,7 @@ const vector& StdMeshers_FaceSide::GetUVPtStruct(bool isXConst, if ( u2nodeVec.empty() ) for ( size_t i = 0; i < nodes.size(); ++i ) { - double u = helper.GetNodeU( myEdge[iE], nodes[i], 0, ¶mOK ); + double u = eHelper.GetNodeU( myEdge[iE], nodes[i], 0, ¶mOK ); // paramSize is signed so orientation is taken into account double normPar = prevNormPar + r * ( u - myFirst[iE] ) / paramSize; u2nodeVec.push_back( make_pair( normPar, nodes[i] )); @@ -401,10 +404,11 @@ const vector& StdMeshers_FaceSide::GetUVPtStruct(bool isXConst, } } // loop on myEdge's - if ( u2node.empty() ) return myPoints; - // Add 2nd VERTEX node for a last EDGE + if ( !proxySubMesh.back() ) { + if ( u2node.empty() ) return myPoints; + const SMDS_MeshNode* node; if ( IsClosed() ) node = u2node.begin()->second; @@ -576,7 +580,9 @@ std::vector StdMeshers_FaceSide::GetOrderedNodes(int theEd if ( NbEdges() == 0 ) return resultNodes; SMESHDS_Mesh* meshDS = myProxyMesh->GetMeshDS(); - SMESH_MesherHelper helper(*myProxyMesh->GetMesh()); + SMESH_MesherHelper eHelper( *myProxyMesh->GetMesh() ); + SMESH_MesherHelper fHelper( *myProxyMesh->GetMesh() ); + fHelper.SetSubShape( myFace ); bool paramOK = true; // Sort nodes of all edges putting them into a map @@ -606,7 +612,8 @@ std::vector StdMeshers_FaceSide::GetOrderedNodes(int theEd // Add 1st vertex node of a current EDGE const SMDS_MeshNode* node = VertexNode( iE ); if ( node ) { // nodes on internal vertices may be missing - if ( vertexNodes.insert( node ).second ) + if ( vertexNodes.insert( node ).second || + fHelper.IsRealSeam( node->getshapeId() )) u2node.insert( make_pair( prevNormPar, node )); } else if ( iE == 0 ) @@ -632,11 +639,11 @@ std::vector StdMeshers_FaceSide::GetOrderedNodes(int theEd { double paramSize = myLast[iE] - myFirst[iE]; double r = myNormPar[iE] - prevNormPar; - helper.SetSubShape( myEdge[iE] ); - helper.ToFixNodeParameters( true ); + eHelper.SetSubShape( myEdge[iE] ); + eHelper.ToFixNodeParameters( true ); for ( size_t i = 0; i < nodes.size(); ++i ) { - double u = helper.GetNodeU( myEdge[iE], nodes[i], 0, ¶mOK ); + double u = eHelper.GetNodeU( myEdge[iE], nodes[i], 0, ¶mOK ); // paramSize is signed so orientation is taken into account double normPar = prevNormPar + r * ( u - myFirst[iE] ) / paramSize; u2node.insert( u2node.end(), make_pair( normPar, nodes[i] )); @@ -707,9 +714,8 @@ bool StdMeshers_FaceSide::GetEdgeNodes(size_t i, if ( inlude1stVertex ) { - const SMDS_MeshNode* n0 = VertexNode( i ); - if ( !n0 ) return false; - nodes.push_back( n0 ); + if ( const SMDS_MeshNode* n0 = VertexNode( i )) + nodes.push_back( n0 ); } if ( sm && ( sm->NbElements() > 0 || sm->NbNodes() > 0 )) @@ -764,9 +770,8 @@ bool StdMeshers_FaceSide::GetEdgeNodes(size_t i, if ( inludeLastVertex ) { - const SMDS_MeshNode* n1 = VertexNode( i+1 ); - if ( !n1 ) return false; - nodes.push_back( n1 ); + if ( const SMDS_MeshNode* n1 = VertexNode( i+1 )) + nodes.push_back( n1 ); } return true; } @@ -943,27 +948,43 @@ int StdMeshers_FaceSide::NbPoints(const bool update) const me->myNbSegments = 0; me->myMissingVertexNodes = false; + vector nodes; for ( int i = 0; i < NbEdges(); ++i ) { - if ( const SMESHDS_SubMesh* sm = myProxyMesh->GetSubMesh( Edge(i) )) { - int nbN = sm->NbNodes(); - if ( sm->NbElements() > 0 ) { - nbN = sm->NbElements() - 1; // nodes can be moved to other shapes by MergeNodes() - if ( !myIgnoreMediumNodes && - sm->GetElements()->next()->IsQuadratic() ) - nbN += sm->NbElements(); + if ( const SMESHDS_SubMesh* sm = myProxyMesh->GetSubMesh( Edge(i) )) + { + if ( sm->NbNodes() == sm->NbElements() - 1 ) + { + me->myNbPonits += sm->NbNodes(); + if ( myIgnoreMediumNodes && sm->IsQuadratic() ) + me->myNbPonits -= sm->NbElements(); + } + else // nodes can be moved to other shapes by MergeNodes() + { + nodes.clear(); + GetEdgeNodes( i, nodes, /*v1=*/false, /*v2=*/false ); + me->myNbPonits += nodes.size(); } - me->myNbPonits += nbN; me->myNbSegments += sm->NbElements(); } } + SMESH_MesherHelper helper( *myProxyMesh->GetMesh() ); + helper.SetSubShape( myFace ); + std::set< const SMDS_MeshNode* > vNodes; - for ( int i = 0; i <= NbEdges(); ++i ) + for ( int i = 0; i <= NbEdges(); ++i ) // nb VERTEXes is more than NbEdges() if !IsClosed() if ( const SMDS_MeshNode* n = VertexNode( i )) - vNodes.insert( n ); + { + if ( !vNodes.insert( n ).second && + helper.IsRealSeam( n->getshapeId() ) && + i < NbEdges()) + me->myNbPonits++; + } else + { me->myMissingVertexNodes = true; + } me->myNbPonits += vNodes.size(); if ( IsClosed() ) diff --git a/src/StdMeshers/StdMeshers_Projection_2D.cxx b/src/StdMeshers/StdMeshers_Projection_2D.cxx index d038ded9f..87572c18f 100644 --- a/src/StdMeshers/StdMeshers_Projection_2D.cxx +++ b/src/StdMeshers/StdMeshers_Projection_2D.cxx @@ -513,18 +513,18 @@ namespace { if ( !tgtNodes.empty() ) { vector< const SMDS_MeshNode* >::iterator tn = tgtNodes.begin(); - if ( srcWire->Edge(iE).Orientation() == tgtWire->Edge(iE).Orientation() ) + //if ( srcWire->Edge(iE).Orientation() == tgtWire->Edge(iE).Orientation() ) { vector< const SMDS_MeshNode* >::iterator sn = srcNodes.begin(); for ( ; tn != tgtNodes.end(); ++tn, ++sn) src2tgtNodes.insert( make_pair( *sn, *tn )); } - else - { - vector< const SMDS_MeshNode* >::reverse_iterator sn = srcNodes.rbegin(); - for ( ; tn != tgtNodes.end(); ++tn, ++sn) - src2tgtNodes.insert( make_pair( *sn, *tn )); - } + // else + // { + // vector< const SMDS_MeshNode* >::reverse_iterator sn = srcNodes.rbegin(); + // for ( ; tn != tgtNodes.end(); ++tn, ++sn) + // src2tgtNodes.insert( make_pair( *sn, *tn )); + // } is1DComputed = true; } } diff --git a/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx b/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx index 30c91c4cd..c173428be 100644 --- a/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx +++ b/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx @@ -4276,9 +4276,12 @@ int StdMeshers_Quadrangle_2D::getCorners(const TopoDS_Face& theFace, return error(COMPERR_BAD_SHAPE, TComm("Face must have 4 sides but not ") << faceSide.NbEdges() ); - const int nbSegments = Max( faceSide.NbPoints()-1, faceSide.NbSegments() ); - if ( nbSegments < nbCorners ) - return error(COMPERR_BAD_INPUT_MESH, TComm("Too few boundary nodes: ") << nbSegments); + if ( theConsiderMesh ) + { + const int nbSegments = Max( faceSide.NbPoints()-1, faceSide.NbSegments() ); + if ( nbSegments < nbCorners ) + return error(COMPERR_BAD_INPUT_MESH, TComm("Too few boundary nodes: ") << nbSegments); + } if ( nbCorners == 3 ) {