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 )
{