X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSMESH%2FSMESH_MesherHelper.cxx;h=bcdd2096a0e5f22528ef9bec48357005c07124e7;hb=f93e9c7865f722b93fbc4c477eb54c7bed921f20;hp=33e7ceb7095ad56ce42796bf252c13cd1f0af6ad;hpb=0c16e57723ec8522693f2f0b6d3216b4f4e3d686;p=modules%2Fsmesh.git diff --git a/src/SMESH/SMESH_MesherHelper.cxx b/src/SMESH/SMESH_MesherHelper.cxx index 33e7ceb70..bcdd2096a 100644 --- a/src/SMESH/SMESH_MesherHelper.cxx +++ b/src/SMESH/SMESH_MesherHelper.cxx @@ -89,9 +89,16 @@ SMESH_MesherHelper::SMESH_MesherHelper(SMESH_Mesh& theMesh) SMESH_MesherHelper::~SMESH_MesherHelper() { - TID2Projector::iterator i_proj = myFace2Projector.begin(); - for ( ; i_proj != myFace2Projector.end(); ++i_proj ) - delete i_proj->second; + { + TID2ProjectorOnSurf::iterator i_proj = myFace2Projector.begin(); + for ( ; i_proj != myFace2Projector.end(); ++i_proj ) + delete i_proj->second; + } + { + TID2ProjectorOnCurve::iterator i_proj = myEdge2Projector.begin(); + for ( ; i_proj != myEdge2Projector.end(); ++i_proj ) + delete i_proj->second; + } } //======================================================================= @@ -286,7 +293,7 @@ bool SMESH_MesherHelper::IsMedium(const SMDS_MeshNode* node, TopoDS_Shape SMESH_MesherHelper::GetSubShapeByNode(const SMDS_MeshNode* node, SMESHDS_Mesh* meshDS) { - int shapeID = node->GetPosition()->GetShapeId(); + int shapeID = node->getshapeId(); if ( 0 < shapeID && shapeID <= meshDS->MaxShapeIndex() ) return meshDS->IndexToShape( shapeID ); else @@ -308,6 +315,31 @@ void SMESH_MesherHelper::AddTLinkNode(const SMDS_MeshNode* n1, myTLinkNodeMap.insert( make_pair(link,n12)); } +//================================================================================ +/*! + * \brief Return true if position of nodes on the shape hasn't yet been checked or + * the positions proved to be invalid + */ +//================================================================================ + +bool SMESH_MesherHelper::toCheckPosOnShape(int shapeID ) const +{ + map< int,bool >::const_iterator id_ok = myNodePosShapesValidity.find( shapeID ); + return ( id_ok == myNodePosShapesValidity.end() || !id_ok->second ); +} + +//================================================================================ +/*! + * \brief Set validity of positions of nodes on the shape. + * Once set, validity is not changed + */ +//================================================================================ + +void SMESH_MesherHelper::setPosOnShapeValidity(int shapeID, bool ok ) const +{ + ((SMESH_MesherHelper*)this)->myNodePosShapesValidity.insert( make_pair( shapeID, ok)); +} + //======================================================================= //function : GetUVOnSeam //purpose : Select UV on either of 2 pcurves of a seam edge, closest to the given UV @@ -356,7 +388,7 @@ gp_XY SMESH_MesherHelper::GetNodeUV(const TopoDS_Face& F, static_cast(n->GetPosition()); uv.SetCoord(fpos->GetUParameter(),fpos->GetVParameter()); if ( check ) - uvOK = CheckNodeUV( F, n, uv.ChangeCoord(), BRep_Tool::Tolerance( F )); + uvOK = CheckNodeUV( F, n, uv.ChangeCoord(), 10*MaxTolerance( F )); } else if(Pos->GetTypeOfPosition()==SMDS_TOP_EDGE) { @@ -365,7 +397,7 @@ gp_XY SMESH_MesherHelper::GetNodeUV(const TopoDS_Face& F, // edge and retrieve value from this pcurve const SMDS_EdgePosition* epos = static_cast(n->GetPosition()); - int edgeID = Pos->GetShapeId(); + int edgeID = n->getshapeId(); TopoDS_Edge E = TopoDS::Edge(GetMeshDS()->IndexToShape(edgeID)); double f, l, u = epos->GetUParameter(); Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l); @@ -375,12 +407,12 @@ gp_XY SMESH_MesherHelper::GetNodeUV(const TopoDS_Face& F, else uv.SetCoord(0.,0.); if ( check || !validU ) - uvOK = CheckNodeUV( F, n, uv.ChangeCoord(), BRep_Tool::Tolerance( E ),/*force=*/ !validU ); + uvOK = CheckNodeUV( F, n, uv.ChangeCoord(), 10*MaxTolerance( F ),/*force=*/ !validU ); // for a node on a seam edge select one of UVs on 2 pcurves if ( n2 && IsSeamShape( edgeID ) ) { - uv = GetUVOnSeam( uv, GetNodeUV( F, n2, 0 )); + uv = GetUVOnSeam( uv, GetNodeUV( F, n2, 0, check )); } else { // adjust uv to period @@ -400,7 +432,7 @@ gp_XY SMESH_MesherHelper::GetNodeUV(const TopoDS_Face& F, } else if(Pos->GetTypeOfPosition()==SMDS_TOP_VERTEX) { - if ( int vertexID = n->GetPosition()->GetShapeId() ) { + if ( int vertexID = n->getshapeId() ) { const TopoDS_Vertex& V = TopoDS::Vertex(GetMeshDS()->IndexToShape(vertexID)); try { uv = BRep_Tool::Parameters( V, F ); @@ -470,8 +502,12 @@ bool SMESH_MesherHelper::CheckNodeUV(const TopoDS_Face& F, const double tol, const bool force) const { - if ( force || !myOkNodePosShapes.count( n->GetPosition()->GetShapeId() )) + int shapeID = n->getshapeId(); + if ( force || toCheckPosOnShape( shapeID )) { + double toldis = tol; + double tolmin = 1.e-7*myMesh->GetMeshDS()->getMaxDim(); // nodes coordinates are stored in float format + if (toldis < tolmin) toldis = tolmin; // check that uv is correct TopLoc_Location loc; Handle(Geom_Surface) surface = BRep_Tool::Surface( F,loc ); @@ -479,8 +515,9 @@ bool SMESH_MesherHelper::CheckNodeUV(const TopoDS_Face& F, if ( !loc.IsIdentity() ) nodePnt.Transform( loc.Transformation().Inverted() ); if ( Precision::IsInfinite( uv.X() ) || Precision::IsInfinite( uv.Y() ) || - nodePnt.Distance( surface->Value( uv.X(), uv.Y() )) > tol ) + nodePnt.Distance( surface->Value( uv.X(), uv.Y() )) > toldis ) { + setPosOnShapeValidity( shapeID, false ); // uv incorrect, project the node to surface GeomAPI_ProjectPointOnSurf& projector = GetProjector( F, loc, tol ); projector.Perform( nodePnt ); @@ -491,16 +528,20 @@ bool SMESH_MesherHelper::CheckNodeUV(const TopoDS_Face& F, } Quantity_Parameter U,V; projector.LowerDistanceParameters(U,V); - if ( nodePnt.Distance( surface->Value( U, V )) > tol ) + uv.SetCoord( U,V ); + if ( nodePnt.Distance( surface->Value( U, V )) > toldis ) { MESSAGE( "SMESH_MesherHelper::CheckNodeUV(), invalid projection" ); return false; } - uv.SetCoord( U,V ); + // store the fixed UV on the face + if ( myShape.IsSame(F) && shapeID == myShapeID ) + const_cast(n)->SetPosition + ( SMDS_PositionPtr( new SMDS_FacePosition( U, V ))); } else if ( uv.Modulus() > numeric_limits::min() ) { - ((SMESH_MesherHelper*) this)->myOkNodePosShapes.insert( n->GetPosition()->GetShapeId() ); + setPosOnShapeValidity( shapeID, true ); } } return true; @@ -517,8 +558,8 @@ GeomAPI_ProjectPointOnSurf& SMESH_MesherHelper::GetProjector(const TopoDS_Face& { Handle(Geom_Surface) surface = BRep_Tool::Surface( F,loc ); int faceID = GetMeshDS()->ShapeToIndex( F ); - TID2Projector& i2proj = const_cast< TID2Projector&>( myFace2Projector ); - TID2Projector::iterator i_proj = i2proj.find( faceID ); + TID2ProjectorOnSurf& i2proj = const_cast< TID2ProjectorOnSurf&>( myFace2Projector ); + TID2ProjectorOnSurf::iterator i_proj = i2proj.find( faceID ); if ( i_proj == i2proj.end() ) { if ( tol == 0 ) tol = BRep_Tool::Tolerance( F ); @@ -619,7 +660,7 @@ double SMESH_MesherHelper::GetNodeU(const TopoDS_Edge& E, else { SMESHDS_Mesh * meshDS = GetMeshDS(); - int vertexID = pos->GetShapeId(); + int vertexID = n->getshapeId(); const TopoDS_Vertex& V = TopoDS::Vertex(meshDS->IndexToShape(vertexID)); param = BRep_Tool::Parameter( V, E ); } @@ -630,9 +671,9 @@ double SMESH_MesherHelper::GetNodeU(const TopoDS_Edge& E, double f,l; BRep_Tool::Range( E, f,l ); bool force = ( param < f-tol || param > l+tol ); if ( !force && pos->GetTypeOfPosition()==SMDS_TOP_EDGE ) - force = ( GetMeshDS()->ShapeToIndex( E ) != pos->GetShapeId() ); + force = ( GetMeshDS()->ShapeToIndex( E ) != n->getshapeId() ); - *check = CheckNodeU( E, n, param, tol, force ); + *check = CheckNodeU( E, n, param, 2*tol, force ); } return param; } @@ -647,10 +688,15 @@ bool SMESH_MesherHelper::CheckNodeU(const TopoDS_Edge& E, const SMDS_MeshNode* n, double& u, const double tol, - const bool force) const + const bool force, + double* distance) const { - if ( force || !myOkNodePosShapes.count( n->GetPosition()->GetShapeId() )) + int shapeID = n->getshapeId(); + if ( force || toCheckPosOnShape( shapeID )) { + double toldis = tol; + double tolmin = 1.e-7*myMesh->GetMeshDS()->getMaxDim(); // nodes coordinates are stored in float format + if (toldis < tolmin) toldis = tolmin; // check that u is correct TopLoc_Location loc; double f,l; Handle(Geom_Curve) curve = BRep_Tool::Curve( E,loc,f,l ); @@ -666,26 +712,46 @@ bool SMESH_MesherHelper::CheckNodeU(const TopoDS_Edge& E, { gp_Pnt nodePnt = SMESH_MeshEditor::TNodeXYZ( n ); if ( !loc.IsIdentity() ) nodePnt.Transform( loc.Transformation().Inverted() ); - if ( nodePnt.Distance( curve->Value( u )) > tol ) + double dist = nodePnt.Distance( curve->Value( u )); + if ( distance ) *distance = dist; + if ( dist > toldis ) { + setPosOnShapeValidity( shapeID, false ); // u incorrect, project the node to the curve - GeomAPI_ProjectPointOnCurve projector( nodePnt, curve, f, l ); - if ( projector.NbPoints() < 1 ) + int edgeID = GetMeshDS()->ShapeToIndex( E ); + TID2ProjectorOnCurve& i2proj = const_cast< TID2ProjectorOnCurve&>( myEdge2Projector ); + TID2ProjectorOnCurve::iterator i_proj = + i2proj.insert( make_pair( edgeID, (GeomAPI_ProjectPointOnCurve*) 0 )).first; + if ( !i_proj->second ) + { + i_proj->second = new GeomAPI_ProjectPointOnCurve(); + i_proj->second->Init( curve, f, l ); + } + GeomAPI_ProjectPointOnCurve* projector = i_proj->second; + projector->Perform( nodePnt ); + if ( projector->NbPoints() < 1 ) { MESSAGE( "SMESH_MesherHelper::CheckNodeU() failed to project" ); return false; } - Quantity_Parameter U = projector.LowerDistanceParameter(); - if ( nodePnt.Distance( curve->Value( U )) > tol ) + Quantity_Parameter U = projector->LowerDistanceParameter(); + u = double( U ); + dist = nodePnt.Distance( curve->Value( U )); + if ( distance ) *distance = dist; + if ( dist > toldis ) { MESSAGE( "SMESH_MesherHelper::CheckNodeU(), invalid projection" ); + MESSAGE("distance " << nodePnt.Distance(curve->Value( U )) << " " << toldis); return false; } - u = double( U ); + // store the fixed U on the edge + if ( myShape.IsSame(E) && shapeID == myShapeID ) + const_cast(n)->SetPosition + ( SMDS_PositionPtr( new SMDS_EdgePosition( U ))); } else if ( fabs( u ) > numeric_limits::min() ) { - ((SMESH_MesherHelper*) this)->myOkNodePosShapes.insert( n->GetPosition()->GetShapeId() ); + setPosOnShapeValidity( shapeID, true ); } if (( u < f-tol || u > l+tol ) && force ) { @@ -728,31 +794,36 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1, SMDS_MeshNode* n12; SMESHDS_Mesh* meshDS = GetMeshDS(); + if ( IsSeamShape( n1->getshapeId() )) + // to get a correct UV of a node on seam, the second node must have checked UV + std::swap( n1, n2 ); + // get type of shape for the new medium node int faceID = -1, edgeID = -1; const SMDS_PositionPtr Pos1 = n1->GetPosition(); const SMDS_PositionPtr Pos2 = n2->GetPosition(); + TopoDS_Edge E; double u [2]; + TopoDS_Face F; gp_XY uv[2]; + bool uvOK[2] = { false, false }; + if( myShape.IsNull() ) { if( Pos1->GetTypeOfPosition()==SMDS_TOP_FACE ) { - faceID = Pos1->GetShapeId(); + faceID = n1->getshapeId(); } else if( Pos2->GetTypeOfPosition()==SMDS_TOP_FACE ) { - faceID = Pos2->GetShapeId(); + faceID = n2->getshapeId(); } if( Pos1->GetTypeOfPosition()==SMDS_TOP_EDGE ) { - edgeID = Pos1->GetShapeId(); + edgeID = n1->getshapeId(); } if( Pos2->GetTypeOfPosition()==SMDS_TOP_EDGE ) { - edgeID = Pos2->GetShapeId(); + edgeID = n2->getshapeId(); } } // get positions of the given nodes on shapes - TopoDS_Edge E; double u [2]; - TopoDS_Face F; gp_XY uv[2]; - bool uvOK[2] = { false, false }; TopAbs_ShapeEnum shapeType = myShape.IsNull() ? TopAbs_SHAPE : myShape.ShapeType(); if ( faceID>0 || shapeType == TopAbs_FACE) { @@ -767,6 +838,11 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1, } else if (edgeID>0 || shapeType == TopAbs_EDGE) { + if ( Pos1->GetTypeOfPosition()==SMDS_TOP_EDGE && + Pos2->GetTypeOfPosition()==SMDS_TOP_EDGE && + n1->getshapeId() != n2->getshapeId() ) // issue 0021006 + return getMediumNodeOnComposedWire(n1,n2,force3d); + if( myShape.IsNull() ) E = TopoDS::Edge(meshDS->IndexToShape(edgeID)); else { @@ -784,10 +860,10 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1, { if ( uvOK[0] && uvOK[1] ) { - if ( IsDegenShape( Pos1->GetShapeId() )) + if ( IsDegenShape( n1->getshapeId() )) if ( myParIndex & U_periodic ) uv[0].SetCoord( 1, uv[1].Coord( 1 )); else uv[0].SetCoord( 2, uv[1].Coord( 2 )); - else if ( IsDegenShape( Pos2->GetShapeId() )) + else if ( IsDegenShape( n2->getshapeId() )) if ( myParIndex & U_periodic ) uv[1].SetCoord( 1, uv[0].Coord( 1 )); else uv[1].SetCoord( 2, uv[0].Coord( 2 )); @@ -826,31 +902,106 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1, } } } + // 3d variant double x = ( n1->X() + n2->X() )/2.; double y = ( n1->Y() + n2->Y() )/2.; double z = ( n1->Z() + n2->Z() )/2.; n12 = meshDS->AddNode(x,y,z); + if ( !F.IsNull() ) { gp_XY UV = ( uv[0] + uv[1] ) / 2.; - CheckNodeUV( F, n12, UV, BRep_Tool::Tolerance( F ), /*force=*/true); + CheckNodeUV( F, n12, UV, 2*BRep_Tool::Tolerance( F ), /*force=*/true); meshDS->SetNodeOnFace(n12, faceID, UV.X(), UV.Y() ); } else if ( !E.IsNull() ) { double U = ( u[0] + u[1] ) / 2.; - CheckNodeU( E, n12, U, BRep_Tool::Tolerance( E ), /*force=*/true); + CheckNodeU( E, n12, U, 2*BRep_Tool::Tolerance( E ), /*force=*/true); meshDS->SetNodeOnEdge(n12, edgeID, U); } - else if ( myShapeID > 1 ) + else if ( myShapeID > 0 ) { meshDS->SetNodeInVolume(n12, myShapeID); } + myTLinkNodeMap.insert( make_pair( link, n12 )); return n12; } +//================================================================================ +/*! + * \brief Makes a medium node if nodes reside different edges + */ +//================================================================================ + +const SMDS_MeshNode* SMESH_MesherHelper::getMediumNodeOnComposedWire(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + bool force3d) +{ + gp_Pnt middle = 0.5 * XYZ(n1) + 0.5 * XYZ(n2); + SMDS_MeshNode* n12 = AddNode( middle.X(), middle.Y(), middle.Z() ); + + // To find position on edge and 3D position for n12, + // project to 2 edges and select projection most close to + + double u = 0, distMiddleProj = Precision::Infinite(); + int iOkEdge = 0; + TopoDS_Edge edges[2]; + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + // get an edge + const SMDS_MeshNode* n = is2nd ? n2 : n1; + TopoDS_Shape shape = GetSubShapeByNode( n, GetMeshDS() ); + if ( shape.IsNull() || shape.ShapeType() != TopAbs_EDGE ) + continue; + + // project to get U of projection and distance from middle to projection + TopoDS_Edge edge = edges[ is2nd ] = TopoDS::Edge( shape ); + double node2MiddleDist = middle.Distance( XYZ(n) ); + double foundU = GetNodeU( edge, n ), foundDist = node2MiddleDist; + CheckNodeU( edge, n12, foundU, 2*BRep_Tool::Tolerance(edge), /*force=*/true, &foundDist ); + if ( foundDist < node2MiddleDist ) + { + distMiddleProj = foundDist; + u = foundU; + iOkEdge = is2nd; + } + } + if ( Precision::IsInfinite( distMiddleProj )) + { + // both projections failed; set n12 on the edge of n1 with U of a common vertex + TopoDS_Vertex vCommon; + if ( TopExp::CommonVertex( edges[0], edges[1], vCommon )) + u = BRep_Tool::Parameter( vCommon, edges[0] ); + else + { + double f,l, u0 = GetNodeU( edges[0], n1 ); + BRep_Tool::Range( edges[0],f,l ); + u = ( fabs(u0-f) < fabs(u0-l) ) ? f : l; + } + iOkEdge = 0; + distMiddleProj = 0; + } + + // move n12 to position of a successfull projection + double tol = BRep_Tool::Tolerance(edges[ iOkEdge ]); + if ( !force3d && distMiddleProj > 2*tol ) + { + TopLoc_Location loc; double f,l; + Handle(Geom_Curve) curve = BRep_Tool::Curve( edges[iOkEdge],loc,f,l ); + gp_Pnt p = curve->Value( u ); + GetMeshDS()->MoveNode( n12, p.X(), p.Y(), p.Z() ); + } + + GetMeshDS()->SetNodeOnEdge(n12, edges[iOkEdge], u); + + myTLinkNodeMap.insert( make_pair( SMESH_TLink(n1,n2), n12 )); + + return n12; +} + //======================================================================= //function : AddNode //purpose : Creates a node @@ -1006,6 +1157,45 @@ SMDS_MeshFace* SMESH_MesherHelper::AddFace(const SMDS_MeshNode* n1, return elem; } +//======================================================================= +//function : AddPolygonalFace +//purpose : Creates polygon, with additional nodes in quadratic mesh +//======================================================================= + +SMDS_MeshFace* SMESH_MesherHelper::AddPolygonalFace (const vector& nodes, + const int id, + const bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshFace* elem = 0; + + if(!myCreateQuadratic) { + if(id) + elem = meshDS->AddPolygonalFaceWithID(nodes, id); + else + elem = meshDS->AddPolygonalFace(nodes); + } + else { + vector newNodes; + for ( int i = 0; i < nodes.size(); ++i ) + { + const SMDS_MeshNode* n1 = nodes[i]; + const SMDS_MeshNode* n2 = nodes[(i+1)/nodes.size()]; + const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); + newNodes.push_back( n1 ); + newNodes.push_back( n12 ); + } + if(id) + elem = meshDS->AddPolygonalFaceWithID(newNodes, id); + else + elem = meshDS->AddPolygonalFace(newNodes); + } + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( elem, myShapeID ); + + return elem; +} + //======================================================================= //function : AddVolume //purpose : Creates quadratic or linear prism @@ -1196,6 +1386,62 @@ SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1, return elem; } +//======================================================================= +//function : AddPolyhedralVolume +//purpose : Creates polyhedron. In quadratic mesh, adds medium nodes +//======================================================================= + +SMDS_MeshVolume* +SMESH_MesherHelper::AddPolyhedralVolume (const std::vector& nodes, + const std::vector& quantities, + const int id, + const bool force3d) +{ + SMESHDS_Mesh * meshDS = GetMeshDS(); + SMDS_MeshVolume* elem = 0; + if(!myCreateQuadratic) + { + if(id) + elem = meshDS->AddPolyhedralVolumeWithID(nodes, quantities, id); + else + elem = meshDS->AddPolyhedralVolume(nodes, quantities); + } + else + { + vector newNodes; + vector newQuantities; + for ( int iFace=0, iN=0; iFace < quantities.size(); ++iFace) + { + int nbNodesInFace = quantities[iFace]; + newQuantities.push_back(0); + for ( int i = 0; i < nbNodesInFace; ++i ) + { + const SMDS_MeshNode* n1 = nodes[ iN + i ]; + newNodes.push_back( n1 ); + newQuantities.back()++; + + const SMDS_MeshNode* n2 = nodes[ iN + ( i+1==nbNodesInFace ? 0 : i+1 )]; +// if ( n1->GetPosition()->GetTypeOfPosition() != SMDS_TOP_3DSPACE && +// n2->GetPosition()->GetTypeOfPosition() != SMDS_TOP_3DSPACE ) + { + const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); + newNodes.push_back( n12 ); + newQuantities.back()++; + } + } + iN += nbNodesInFace; + } + if(id) + elem = meshDS->AddPolyhedralVolumeWithID( newNodes, newQuantities, id ); + else + elem = meshDS->AddPolyhedralVolume( newNodes, newQuantities ); + } + if ( mySetElemOnShape && myShapeID > 0 ) + meshDS->SetMeshElementOnShape( elem, myShapeID ); + + return elem; +} + //======================================================================= //function : LoadNodeColumns //purpose : Load nodes bound to face into a map of node columns @@ -1343,6 +1589,26 @@ bool SMESH_MesherHelper::IsSubShape( const TopoDS_Shape& shape, SMESH_Mesh* aMes shape.ShapeType() == TopAbs_COMPOUND && aMesh->GetMeshDS()->IsGroupOfSubShapes( shape ); } +//================================================================================ +/*! + * \brief Return maximal tolerance of shape + */ +//================================================================================ + +double SMESH_MesherHelper::MaxTolerance( const TopoDS_Shape& shape ) +{ + double tol = Precision::Confusion(); + TopExp_Explorer exp; + for ( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() ) + tol = Max( tol, BRep_Tool::Tolerance( TopoDS::Face( exp.Current()))); + for ( exp.Init( shape, TopAbs_EDGE ); exp.More(); exp.Next() ) + tol = Max( tol, BRep_Tool::Tolerance( TopoDS::Edge( exp.Current()))); + for ( exp.Init( shape, TopAbs_VERTEX ); exp.More(); exp.Next() ) + tol = Max( tol, BRep_Tool::Tolerance( TopoDS::Vertex( exp.Current()))); + + return tol; +} + //======================================================================= //function : IsQuadraticMesh //purpose : Check mesh without geometry for: if all elements on this shape are quadratic, @@ -1388,16 +1654,23 @@ double SMESH_MesherHelper::GetOtherParam(const double param) const return fabs(param-myPar1[i]) < fabs(param-myPar2[i]) ? myPar2[i] : myPar1[i]; } +//#include + //======================================================================= namespace { // Structures used by FixQuadraticElements() //======================================================================= #define __DMP__(txt) \ -//cout << txt + //cout << txt #define MSG(txt) __DMP__(txt< < 1/15 * + return middleNodeMove2 < 1/15./15. * linkLen2; + } struct QFace; // --------------------------------------- @@ -1434,16 +1707,18 @@ namespace { // Structures used by FixQuadraticElements() { _nodeMove += move; _nbMoves += sum ? (_nbMoves==0) : 1; } gp_XYZ Move() const { return _nodeMove.XYZ() / _nbMoves; } bool IsMoved() const { return (_nbMoves > 0 && !IsStraight()); } - bool IsStraight() const { return _nodeMove.SquareMagnitude() <= straightTol2; } - + bool IsStraight() const + { return isStraightLink( (XYZ(node1())-XYZ(node2())).SquareModulus(), + _nodeMove.SquareMagnitude()); + } bool operator<(const QLink& other) const { return (node1()->GetID() == other.node1()->GetID() ? node2()->GetID() < other.node2()->GetID() : node1()->GetID() < other.node1()->GetID()); } - struct PtrComparator { - bool operator() (const QLink* l1, const QLink* l2 ) const { return *l1 < *l2; } - }; +// struct PtrComparator { +// bool operator() (const QLink* l1, const QLink* l2 ) const { return *l1 < *l2; } +// }; }; // --------------------------------------------------------- /*! @@ -1457,7 +1732,7 @@ namespace { // Structures used by FixQuadraticElements() TChainLink(const QLink* qlink=0):_qlink(qlink) { _qfaces[0] = _qfaces[1] = 0; } - void SetFace(const QFace* face) { int iF = _qfaces[0] ? 1 : 0; _qfaces[iF]=face; } + void SetFace(const QFace* face) const { int iF = _qfaces[0] ? 1 : 0; _qfaces[iF]=face; } bool IsBoundary() const { return !_qfaces[1]; } @@ -1490,7 +1765,7 @@ namespace { // Structures used by FixQuadraticElements() /*! * \brief Face shared by two volumes and bound by QLinks */ - struct QFace: public TIDSortedElemSet + struct QFace: public TIDSortedNodeSet { mutable const SMDS_MeshElement* _volumes[2]; mutable vector< const QLink* > _sides; @@ -1529,6 +1804,8 @@ namespace { // Structures used by FixQuadraticElements() bool Contains( const SMDS_MeshNode* node ) const { return count(node); } + bool IsSpoiled(const QLink* bentLink ) const; + TLinkInSet GetBoundaryLink( const TLinkSet& links, const TChainLink& avoidLink, TLinkInSet * notBoundaryLink = 0, @@ -1573,7 +1850,7 @@ namespace { // Structures used by FixQuadraticElements() ostream& operator << (ostream& out, const QFace& f) { out <<"QFace nodes: "/*<< &f << " "*/; - for ( TIDSortedElemSet::const_iterator n = f.begin(); n != f.end(); ++n ) + for ( TIDSortedNodeSet::const_iterator n = f.begin(); n != f.end(); ++n ) out << (*n)->GetID() << " "; out << " \tvolumes: " << (f._volumes[0] ? f._volumes[0]->GetID() : 0) << " " @@ -1616,7 +1893,7 @@ namespace { // Structures used by FixQuadraticElements() } //================================================================================ /*! - * \brief Make up chain of links + * \brief Make up a chain of links * \param iSide - link to add first * \param chain - chain to fill in * \param pos - postion of medium nodes the links should have @@ -1635,22 +1912,33 @@ namespace { // Structures used by FixQuadraticElements() if ( _sides.size() != 4 ) { // triangle - visit all my continous faces MSGBEG( *this ); + TLinkSet links; list< const QFace* > faces( 1, this ); - for (list< const QFace* >::iterator fIt = faces.begin(); fIt != faces.end(); ++fIt ) { - const QFace* face = *fIt; + while ( !faces.empty() ) { + const QFace* face = faces.front(); for ( int i = 0; i < face->_sides.size(); ++i ) { if ( !face->_sideIsAdded[i] && face->_sides[i] ) { face->_sideIsAdded[i] = true; - TChain::iterator chLink = chain.insert( chain.begin(), TChainLink(face->_sides[i])); + // find a face side in the chain + TLinkInSet chLink = links.insert( TChainLink(face->_sides[i])).first; +// TChain::iterator chLink = chain.begin(); +// for ( ; chLink != chain.end(); ++chLink ) +// if ( chLink->_qlink == face->_sides[i] ) +// break; +// if ( chLink == chain.end() ) +// chLink = chain.insert( chain.begin(), TChainLink(face->_sides[i])); + // add a face to a chained link and put a continues face in the queue chLink->SetFace( face ); if ( face->_sides[i]->MediumPos() >= pos ) if ( const QFace* contFace = face->_sides[i]->GetContinuesFace( face )) faces.push_back( contFace ); } } + faces.pop_front(); } if ( error < ERR_TRI ) error = ERR_TRI; + chain.insert( chain.end(), links.begin(),links.end() ); return false; } _sideIsAdded[iSide] = true; // not to add this link to chain again @@ -1716,7 +2004,7 @@ namespace { // Structures used by FixQuadraticElements() TLinkInSet link = links.find( _sides[iL] ); if ( link == linksEnd ) continue; if ( (*link)->MediumPos() > SMDS_TOP_FACE ) - continue; // We work on faces here, don't go into a volume + continue; // We work on faces here, don't go inside a solid // check link if ( link->IsBoundary() ) { @@ -1859,7 +2147,8 @@ namespace { // Structures used by FixQuadraticElements() // propagate to adjacent faces till limit step or boundary double len1 = thePrevLen + (theLink->MiddlePnt() - _sides[iL1]->MiddlePnt()).Modulus(); double len2 = thePrevLen + (theLink->MiddlePnt() - _sides[iL2]->MiddlePnt()).Modulus(); - gp_Vec linkDir1, linkDir2; + gp_Vec linkDir1(0,0,0); // initialize to avoid valgrind error ("Conditional jump...") + gp_Vec linkDir2(0,0,0); try { OCC_CATCH_SIGNALS; if ( f1 ) @@ -1903,6 +2192,37 @@ namespace { // Structures used by FixQuadraticElements() return fullLen; } + //================================================================================ + /*! + * \brief Checks if the face is distorted due to bentLink + */ + //================================================================================ + + bool QFace::IsSpoiled(const QLink* bentLink ) const + { + // code is valid for convex faces only + gp_XYZ gc(0,0,0); + for ( TIDSortedNodeSet::const_iterator n = begin(); n!=end(); ++n) + gc += XYZ( *n ) / size(); + for (unsigned i = 0; i < _sides.size(); ++i ) + { + if ( _sides[i] == bentLink ) continue; + gp_Vec linkNorm = _normal ^ gp_Vec( XYZ(_sides[i]->node1()), XYZ(_sides[i]->node2())); + gp_Vec vecOut( gc, _sides[i]->MiddlePnt() ); + if ( linkNorm * vecOut < 0 ) + linkNorm.Reverse(); + double mag2 = linkNorm.SquareMagnitude(); + if ( mag2 > numeric_limits::min() ) + linkNorm /= sqrt( mag2 ); + gp_Vec vecBent ( _sides[i]->MiddlePnt(), bentLink->MediumPnt()); + gp_Vec vecStraight( _sides[i]->MiddlePnt(), bentLink->MiddlePnt()); + if ( vecBent * linkNorm > -0.1*vecStraight.Magnitude() ) + return true; + } + return false; + + } + //================================================================================ /*! * \brief Find pairs of continues faces @@ -2048,41 +2368,20 @@ namespace { // Structures used by FixQuadraticElements() TLinkSet linkSet( allLinks.begin(), allLinks.end()); TLinkInSet linkIt = linkSet.begin(), linksEnd = linkSet.end(); - // move in 2d if we are on geom face -// TopoDS_Face face; -// TopLoc_Location loc; -// SMESH_MesherHelper faceHelper( *helper.GetMesh()); -// while ( linkIt->IsBoundary()) ++linkIt; -// if ( linkIt == linksEnd ) return; -// if ( (*linkIt)->MediumPos() == SMDS_TOP_FACE ) { -// bool checkPos = true; -// TopoDS_Shape f = helper.GetSubShapeByNode( (*linkIt)->_mediumNode, helper.GetMeshDS() ); -// if ( !f.IsNull() && f.ShapeType() == TopAbs_FACE ) { -// face = TopoDS::Face( f ); -// helper.GetNodeUV( face, (*linkIt)->_mediumNode, 0, &checkPos); -// if (checkPos) -// face.Nullify(); -// else -// faceHelper.SetSubShape( face ); -// } -// } for ( linkIt = linkSet.begin(); linkIt != linksEnd; ++linkIt) { if ( linkIt->IsBoundary() && !(*linkIt)->IsStraight() && linkIt->_qfaces[0]) { -// if ( !face.IsNull() ) { -// const SMDS_MeshNode* inFaceNode = -// faceHelper.GetNodeUVneedInFaceNode() ? linkIt->_qfaces[0]->GetNodeInFace() : 0; -// gp_XY uvm = helper.GetNodeUV( face, (*linkIt)->_mediumNode, inFaceNode ); -// gp_XY uv1 = helper.GetNodeUV( face, (*linkIt)->node1(), inFaceNode); -// gp_XY uv2 = helper.GetNodeUV( face, (*linkIt)->node2(), inFaceNode); -// gp_XY uvMove = uvm - helper.GetMiddleUV( BRep_Tool::Surface(face,loc), uv1, uv2); -// gp_Vec move( uvMove.X(), uvMove.Y(), 0 ); -// linkIt->_qfaces[0]->MoveByBoundary( *linkIt, move, linkSet, &faceHelper ); -// } -// else { - linkIt->_qfaces[0]->MoveByBoundary( *linkIt, (*linkIt)->_nodeMove, linkSet ); - //} + // move iff a boundary link is bent towards inside of a face (issue 0021084) + const QFace* face = linkIt->_qfaces[0]; + gp_XYZ pIn = ( face->_sides[0]->MiddlePnt() + + face->_sides[1]->MiddlePnt() + + face->_sides[2]->MiddlePnt() ) / 3.; + gp_XYZ insideDir( pIn - (*linkIt)->MiddlePnt()); + bool linkBentInside = ((*linkIt)->_nodeMove.Dot( insideDir ) > 0 ); + //if ( face->IsSpoiled( linkIt->_qlink )) + if ( linkBentInside ) + face->MoveByBoundary( *linkIt, (*linkIt)->_nodeMove, linkSet ); } } } @@ -2095,7 +2394,7 @@ namespace { // Structures used by FixQuadraticElements() enum TSplitTriaResult { _OK, _NO_CORNERS, _FEW_ROWS, _MANY_ROWS, _NO_SIDELINK, _BAD_MIDQUAD, _NOT_RECT, - _NO_MIDQUAD, _NO_UPTRIA, _BAD_SET_SIZE, _BAD_CORNER, _BAD_START, _NO_BOTLINK }; + _NO_MIDQUAD, _NO_UPTRIA, _BAD_SET_SIZE, _BAD_CORNER, _BAD_START, _NO_BOTLINK, _TWISTED_CHAIN }; TSplitTriaResult splitTrianglesIntoChains( TChain & allLinks, vector< TChain> & resultChains, @@ -2161,6 +2460,8 @@ namespace { // Structures used by FixQuadraticElements() const QFace* botTria = botLink->_qfaces[0]; // bottom triangle bound by botLink if ( !botTria ) { // the column ends + if ( botLink == startLink ) + return _TWISTED_CHAIN; // issue 0020951 linkSet.erase( botLink ); if ( iRow != rowChains.size() ) return _FEW_ROWS; // different nb of rows in columns @@ -2220,8 +2521,10 @@ namespace { // Structures used by FixQuadraticElements() // next bottom link ends at the new corner linkSet.erase( botLink ); botLink = upTria->GetLinkByNode( linkSet, (isCase2 ? *sideLink : *midQuadLink), corner ); - if ( botLink == linksEnd || botLink == (isCase2 ? midQuadLink : sideLink)) + if ( botLink == linksEnd || botLink == midQuadLink || botLink == sideLink) return _NO_BOTLINK; + if ( midQuadLink == startLink || sideLink == startLink ) + return _TWISTED_CHAIN; // issue 0020951 linkSet.erase( midQuadLink ); linkSet.erase( sideLink ); @@ -2265,7 +2568,7 @@ namespace { // Structures used by FixQuadraticElements() return _OK; } -} +} //namespace //======================================================================= /*! @@ -2278,37 +2581,49 @@ namespace { // Structures used by FixQuadraticElements() void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) { - // apply algorithm to solids or geom faces + // 0. Apply algorithm to solids or geom faces // ---------------------------------------------- if ( myShape.IsNull() ) { if ( !myMesh->HasShapeToMesh() ) return; SetSubShape( myMesh->GetShapeToMesh() ); +#ifdef _DEBUG_ + int nbSolids = 0; + TopTools_IndexedMapOfShape solids; + TopExp::MapShapes(myShape,TopAbs_SOLID,solids); + nbSolids = solids.Extent(); +#endif TopTools_MapOfShape faces; // faces not in solid or in not meshed solid for ( TopExp_Explorer f(myShape,TopAbs_FACE,TopAbs_SOLID); f.More(); f.Next() ) { - faces.Add( f.Current() ); + faces.Add( f.Current() ); // not in solid } for ( TopExp_Explorer s(myShape,TopAbs_SOLID); s.More(); s.Next() ) { if ( myMesh->GetSubMesh( s.Current() )->IsEmpty() ) { // get faces of solid for ( TopExp_Explorer f( s.Current(), TopAbs_FACE); f.More(); f.Next() ) - faces.Add( f.Current() ); + faces.Add( f.Current() ); // in not meshed solid } else { // fix nodes in the solid and its faces + MSG("FIX SOLID " << nbSolids-- << " #" << GetMeshDS()->ShapeToIndex(s.Current())); SMESH_MesherHelper h(*myMesh); h.SetSubShape( s.Current() ); h.FixQuadraticElements(false); } } // fix nodes on geom faces +#ifdef _DEBUG_ + int nbfaces = faces.Extent(); +#endif for ( TopTools_MapIteratorOfMapOfShape fIt( faces ); fIt.More(); fIt.Next() ) { + MSG("FIX FACE " << nbfaces-- << " #" << GetMeshDS()->ShapeToIndex(fIt.Key())); SMESH_MesherHelper h(*myMesh); h.SetSubShape( fIt.Key() ); h.FixQuadraticElements(true); } + //perf_print_all_meters(1); return; } - // Find out type of elements and get iterator on them + // 1. Find out type of elements and get iterator on them // --------------------------------------------------- SMDS_ElemIteratorPtr elemIt; @@ -2327,7 +2642,7 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) if ( !elemIt || !elemIt->more() || elemType < SMDSAbs_Face ) return; - // Fill in auxiliary data structures + // 2. Fill in auxiliary data structures // ---------------------------------- set< QLink > links; @@ -2336,8 +2651,8 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) set< QFace >::iterator pFace; bool isCurved = false; - bool hasRectFaces = false; - set nbElemNodeSet; + //bool hasRectFaces = false; + //set nbElemNodeSet; if ( elemType == SMDSAbs_Volume ) { @@ -2350,7 +2665,7 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) for ( int iF = 0; iF < volTool.NbFaces(); ++iF ) // loop on faces of volume { int nbN = volTool.NbFaceNodes( iF ); - nbElemNodeSet.insert( nbN ); + //nbElemNodeSet.insert( nbN ); const SMDS_MeshNode** faceNodes = volTool.GetFaceNodes( iF ); vector< const QLink* > faceLinks( nbN/2 ); for ( int iN = 0; iN < nbN; iN += 2 ) // loop on links of a face @@ -2369,9 +2684,9 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) if ( pFace->NbVolumes() == 0 ) pFace->AddSelfToLinks(); pFace->SetVolume( vol ); - hasRectFaces = hasRectFaces || - ( volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_HEXA || - volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_PENTA ); +// hasRectFaces = hasRectFaces || +// ( volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_HEXA || +// volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_PENTA ); #ifdef _DEBUG_ if ( nbN == 6 ) pFace->_face = GetMeshDS()->FindFace(faceNodes[0],faceNodes[2],faceNodes[4]); @@ -2392,7 +2707,7 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) const SMDS_MeshElement* face = elemIt->next(); if ( !face->IsQuadratic() ) continue; - nbElemNodeSet.insert( face->NbNodes() ); + //nbElemNodeSet.insert( face->NbNodes() ); int nbN = face->NbNodes()/2; vector< const QLink* > faceLinks( nbN ); for ( int iN = 0; iN < nbN; ++iN ) // loop on links of a face @@ -2407,13 +2722,13 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) // store QFace pFace = faces.insert( QFace( faceLinks )).first; pFace->AddSelfToLinks(); - hasRectFaces = ( hasRectFaces || nbN == 4 ); + //hasRectFaces = ( hasRectFaces || nbN == 4 ); } } if ( !isCurved ) return; // no curved edges of faces - // Compute displacement of medium nodes + // 3. Compute displacement of medium nodes // ------------------------------------- // two loops on faces: the first is to treat boundary links, the second is for internal ones @@ -2423,6 +2738,7 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) for ( ; isInside < 2; ++isInside ) { MSG( "--------------- LOOP (inside=" << isInside << ") ------------------"); SMDS_TypeOfPosition pos = isInside ? SMDS_TOP_3DSPACE : SMDS_TOP_FACE; + SMDS_TypeOfPosition bndPos = isInside ? SMDS_TOP_FACE : SMDS_TOP_EDGE; for ( pFace = faces.begin(); pFace != faces.end(); ++pFace ) { if ( bool(isInside) == pFace->IsBoundary() ) @@ -2461,7 +2777,12 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) TChain& chain = chains[iC]; if ( chain.empty() ) continue; if ( chain.front()->IsStraight() && chain.back()->IsStraight() ) { - MSG("3D straight"); + MSG("3D straight - ignore"); + continue; + } + if ( chain.front()->MediumPos() > bndPos || + chain.back()->MediumPos() > bndPos ) { + MSG("Internal chain - ignore"); continue; } // mesure chain length and compute link position along the chain @@ -2498,6 +2819,7 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) { face = TopoDS::Face( f ); Handle(Geom_Surface) surf = BRep_Tool::Surface(face,loc); + bool isStraight[2]; for ( int is1 = 0; is1 < 2; ++is1 ) // move0 or move1 { TChainLink& link = is1 ? chain.back() : chain.front(); @@ -2508,10 +2830,14 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) // uvMove = uvm - uv12 gp_XY uvMove = applyIn2D(surf, uvm, uv12, gp_XY_Subtracted, /*inPeriod=*/false); ( is1 ? move1 : move0 ).SetCoord( uvMove.X(), uvMove.Y(), 0 ); + if ( !is1 ) // correct nodeOnFace for move1 (issue 0020919) + nodeOnFace = (*(++chain.rbegin()))->_mediumNode; + isStraight[is1] = isStraightLink( (uv2-uv1).SquareModulus(),uvMove.SquareModulus()); } - if ( move0.SquareMagnitude() < straightTol2 && - move1.SquareMagnitude() < straightTol2 ) { - MSG("2D straight"); +// if ( move0.SquareMagnitude() < straightTol2 && +// move1.SquareMagnitude() < straightTol2 ) { + if ( isStraight[0] && isStraight[1] ) { + MSG("2D straight - ignore"); continue; // straight - no need to move nodes of internal links } } @@ -2563,7 +2889,8 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) { gp_XY uv0 = GetNodeUV( face, (*link0)->_mediumNode, 0, &checkUV); gp_XY uv2 = GetNodeUV( face, (*link2)->_mediumNode, 0, &checkUV); - MSG( "uv0: "<