X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FStdMeshers%2FStdMeshers_ViscousLayers.cxx;h=8212b0a8b4d4f407e847ce6376be88d99f9a0162;hb=c150e1e4c40479c83b47cfb732f240c5df3b5d62;hp=d6fabf343f92780aecabbd424f602484995a72d4;hpb=e0cbb6f531144291ba38970fd2c3ee4a43b2bd6a;p=modules%2Fsmesh.git diff --git a/src/StdMeshers/StdMeshers_ViscousLayers.cxx b/src/StdMeshers/StdMeshers_ViscousLayers.cxx index d6fabf343..8212b0a8b 100644 --- a/src/StdMeshers/StdMeshers_ViscousLayers.cxx +++ b/src/StdMeshers/StdMeshers_ViscousLayers.cxx @@ -409,7 +409,7 @@ namespace VISCOUS_3D gp_XYZ _normal; // to boundary of solid vector _pos; // points computed during inflation - double _len; // length achived with the last inflation step + double _len; // length achieved with the last inflation step double _maxLen; // maximal possible length double _cosin; // of angle (_normal ^ surface) double _minAngle; // of _simplices @@ -427,23 +427,26 @@ namespace VISCOUS_3D enum EFlags { TO_SMOOTH = 0x0000001, MOVED = 0x0000002, // set by _neibors[i]->SetNewLength() - SMOOTHED = 0x0000004, // set by this->Smooth() + SMOOTHED = 0x0000004, // set by _LayerEdge::Smooth() DIFFICULT = 0x0000008, // near concave VERTEX ON_CONCAVE_FACE = 0x0000010, BLOCKED = 0x0000020, // not to inflate any more INTERSECTED = 0x0000040, // close intersection with a face found NORMAL_UPDATED = 0x0000080, - MARKED = 0x0000100, // local usage - MULTI_NORMAL = 0x0000200, // a normal is invisible by some of surrounding faces - NEAR_BOUNDARY = 0x0000400, // is near FACE boundary forcing smooth - SMOOTHED_C1 = 0x0000800, // is on _eosC1 - DISTORTED = 0x0001000, // was bad before smoothing - RISKY_SWOL = 0x0002000, // SWOL is parallel to a source FACE - UNUSED_FLAG = 0x0100000 + UPD_NORMAL_CONV = 0x0000100, // to update normal on boundary of concave FACE + MARKED = 0x0000200, // local usage + MULTI_NORMAL = 0x0000400, // a normal is invisible by some of surrounding faces + NEAR_BOUNDARY = 0x0000800, // is near FACE boundary forcing smooth + SMOOTHED_C1 = 0x0001000, // is on _eosC1 + DISTORTED = 0x0002000, // was bad before smoothing + RISKY_SWOL = 0x0004000, // SWOL is parallel to a source FACE + SHRUNK = 0x0008000, // target node reached a tgt position while shrink() + UNUSED_FLAG = 0x0100000 // to add user flags after }; bool Is ( int flag ) const { return _flags & flag; } void Set ( int flag ) { _flags |= flag; } void Unset( int flag ) { _flags &= ~flag; } + std::string DumpFlags() const; // debug void SetNewLength( double len, _EdgesOnShape& eos, SMESH_MesherHelper& helper ); bool SetNewLength2d( Handle(Geom_Surface)& surface, @@ -495,7 +498,7 @@ namespace VISCOUS_3D const gp_XYZ& PrevPos() const { return _pos[ _pos.size() - 2 ]; } gp_XYZ PrevCheckPos( _EdgesOnShape* eos=0 ) const; gp_Ax1 LastSegment(double& segLen, _EdgesOnShape& eos) const; - gp_XY LastUV( const TopoDS_Face& F, _EdgesOnShape& eos ) const; + gp_XY LastUV( const TopoDS_Face& F, _EdgesOnShape& eos, int which=-1 ) const; bool IsOnEdge() const { return _2neibors; } gp_XYZ Copy( _LayerEdge& other, _EdgesOnShape& eos, SMESH_MesherHelper& helper ); void SetCosin( double cosin ); @@ -662,6 +665,8 @@ namespace VISCOUS_3D _SolidData* _data; // parent SOLID + _LayerEdge* operator[](size_t i) const { return (_LayerEdge*) _edges[i]; } + size_t size() const { return _edges.size(); } TopAbs_ShapeEnum ShapeType() const { return _shape.IsNull() ? TopAbs_SHAPE : _shape.ShapeType(); } TopAbs_ShapeEnum SWOLType() const @@ -676,7 +681,7 @@ namespace VISCOUS_3D //-------------------------------------------------------------------------------- /*! - * \brief Convex FACE whose radius of curvature is less than the thickness of + * \brief Convex FACE whose radius of curvature is less than the thickness of * layers. It is used to detect distortion of prisms based on a convex * FACE and to update normals to enable further increasing the thickness */ @@ -690,7 +695,14 @@ namespace VISCOUS_3D // map a sub-shape to _SolidData::_edgesOnShape map< TGeomID, _EdgesOnShape* > _subIdToEOS; + bool _isTooCurved; bool _normalsFixed; + bool _normalsFixedOnBorders; // used in putOnOffsetSurface() + + double GetMaxCurvature( _SolidData& data, + _EdgesOnShape& eof, + BRepLProp_SLProps& surfProp, + SMESH_MesherHelper& helper); bool GetCenterOfCurvature( _LayerEdge* ledge, BRepLProp_SLProps& surfProp, @@ -721,6 +733,7 @@ namespace VISCOUS_3D { typedef const StdMeshers_ViscousLayers* THyp; TopoDS_Shape _solid; + TopTools_MapOfShape _before; // SOLIDs to be computed before _solid TGeomID _index; // SOLID id _MeshOfSolid* _proxyMesh; list< THyp > _hyps; @@ -754,8 +767,6 @@ namespace VISCOUS_3D int _nbShapesToSmooth; - //map< TGeomID,Handle(Geom_Curve)> _edge2curve; - vector< _CollisionEdges > _collisionEdges; set< TGeomID > _concaveFaces; @@ -867,6 +878,7 @@ namespace VISCOUS_3D const gp_XY& uvToFix, const double refSign ); }; + struct PyDump; //-------------------------------------------------------------------------------- /*! * \brief Builder of viscous layers @@ -891,6 +903,7 @@ namespace VISCOUS_3D private: bool findSolidsWithLayers(); + bool setBefore( _SolidData& solidBefore, _SolidData& solidAfter ); bool findFacesWithLayers(const bool onlyWith=false); void getIgnoreFaces(const TopoDS_Shape& solid, const StdMeshers_ViscousLayers* hyp, @@ -938,8 +951,11 @@ namespace VISCOUS_3D void makeOffsetSurface( _EdgesOnShape& eos, SMESH_MesherHelper& ); void putOnOffsetSurface( _EdgesOnShape& eos, int infStep, vector< _EdgesOnShape* >& eosC1, - int smooStep=0, bool moveAll=false ); + int smooStep=0, int moveAll=false ); void findCollisionEdges( _SolidData& data, SMESH_MesherHelper& helper ); + void findEdgesToUpdateNormalNearConvexFace( _ConvexFace & convFace, + _SolidData& data, + SMESH_MesherHelper& helper ); void limitMaxLenByCurvature( _SolidData& data, SMESH_MesherHelper& helper ); void limitMaxLenByCurvature( _LayerEdge* e1, _LayerEdge* e2, _EdgesOnShape& eos1, _EdgesOnShape& eos2, @@ -957,7 +973,7 @@ namespace VISCOUS_3D _LayerEdge& edge, const gp_XYZ& newNormal); bool refine(_SolidData& data); - bool shrink(); + bool shrink(_SolidData& data); bool prepareEdgeToShrink( _LayerEdge& edge, _EdgesOnShape& eos, SMESH_MesherHelper& helper, const SMESHDS_SubMesh* faceSubMesh ); @@ -967,7 +983,7 @@ namespace VISCOUS_3D const bool is2D, const int step, set * involvedNodes=NULL); - bool addBoundaryElements(); + bool addBoundaryElements(_SolidData& data); bool error( const string& text, int solidID=-1 ); SMESHDS_Mesh* getMeshDS() const { return _mesh->GetMeshDS(); } @@ -975,11 +991,15 @@ namespace VISCOUS_3D // debug void makeGroupOfLE(); - SMESH_Mesh* _mesh; - SMESH_ComputeErrorPtr _error; + SMESH_Mesh* _mesh; + SMESH_ComputeErrorPtr _error; + + vector< _SolidData > _sdVec; + TopTools_IndexedMapOfShape _solids; // to find _SolidData by a solid + TopTools_MapOfShape _shrinkedFaces; - vector< _SolidData > _sdVec; - int _tmpFaceID; + int _tmpFaceID; + PyDump* _pyDump; }; //-------------------------------------------------------------------------------- /*! @@ -1027,6 +1047,7 @@ namespace VISCOUS_3D size_t _iSeg[2]; // index of segment where extreme tgt node is projected _EdgesOnShape& _eos; double _curveLen; // length of the EDGE + std::pair _eToSmooth[2]; // indices of _LayerEdge's in _eos static Handle(Geom_Curve) CurveForSmooth( const TopoDS_Edge& E, _EdgesOnShape& eos, @@ -1040,31 +1061,24 @@ namespace VISCOUS_3D bool Perform(_SolidData& data, Handle(ShapeAnalysis_Surface)& surface, const TopoDS_Face& F, - SMESH_MesherHelper& helper ) - { - if ( _leParams.empty() || ( !isAnalytic() && _offPoints.empty() )) - prepare( data ); + SMESH_MesherHelper& helper ); - if ( isAnalytic() ) - return smoothAnalyticEdge( data, surface, F, helper ); - else - return smoothComplexEdge ( data, surface, F, helper ); - } void prepare(_SolidData& data ); + void findEdgesToSmooth(); + + bool isToSmooth( int iE ); + bool smoothAnalyticEdge( _SolidData& data, Handle(ShapeAnalysis_Surface)& surface, const TopoDS_Face& F, SMESH_MesherHelper& helper); - bool smoothComplexEdge( _SolidData& data, Handle(ShapeAnalysis_Surface)& surface, const TopoDS_Face& F, SMESH_MesherHelper& helper); - gp_XYZ getNormalNormal( const gp_XYZ & normal, const gp_XYZ& edgeDir); - _LayerEdge* getLEdgeOnV( bool is2nd ) { return _eos._edges[ is2nd ? _eos._edges.size()-1 : 0 ]->_2neibors->_edges[ is2nd ]; @@ -1232,8 +1246,8 @@ StdMeshers_ViscousLayers::Compute(SMESH_Mesh& theMesh, const bool toMakeN2NMap) const { using namespace VISCOUS_3D; - _ViscousBuilder bulder; - SMESH_ComputeErrorPtr err = bulder.Compute( theMesh, theShape ); + _ViscousBuilder builder; + SMESH_ComputeErrorPtr err = builder.Compute( theMesh, theShape ); if ( err && !err->IsOK() ) return SMESH_ProxyMesh::Ptr(); @@ -1245,7 +1259,7 @@ StdMeshers_ViscousLayers::Compute(SMESH_Mesh& theMesh, _ViscousListener::GetSolidMesh( &theMesh, exp.Current(), /*toCreate=*/false)) { if ( toMakeN2NMap && !pm->_n2nMapComputed ) - if ( !bulder.MakeN2NMap( pm )) + if ( !builder.MakeN2NMap( pm )) return SMESH_ProxyMesh::Ptr(); components.push_back( SMESH_ProxyMesh::Ptr( pm )); pm->myIsDeletable = false; // it will de deleted by boost::shared_ptr @@ -1309,8 +1323,8 @@ StdMeshers_ViscousLayers::CheckHypothesis(SMESH_Mesh& t const TopoDS_Shape& theShape, SMESH_Hypothesis::Hypothesis_Status& theStatus) { - VISCOUS_3D::_ViscousBuilder bulder; - SMESH_ComputeErrorPtr err = bulder.CheckHypotheses( theMesh, theShape ); + VISCOUS_3D::_ViscousBuilder builder; + SMESH_ComputeErrorPtr err = builder.CheckHypotheses( theMesh, theShape ); if ( err && !err->IsOK() ) theStatus = SMESH_Hypothesis::HYP_INCOMPAT_HYPS; else @@ -1656,14 +1670,15 @@ namespace VISCOUS_3D // HOWTO use: run python commands written in a console to see // construction steps of viscous layers #ifdef __myDEBUG - ofstream* py; - int theNbPyFunc; - struct PyDump { + ostream* py; + int theNbPyFunc; + struct PyDump + { PyDump(SMESH_Mesh& m) { int tag = 3 + m.GetId(); const char* fname = "/tmp/viscous.py"; cout << "execfile('"< ostream & operator<<( const T &anything ) { return *this ; } + }; + void Pause() { py = &_mystream; } + void Resume() { py = _pyStream; } + MyStream _mystream; + ostream* _pyStream; }; #define dumpFunction(f) { _dumpFunction(f, __LINE__);} #define dumpMove(n) { _dumpMove(n, __LINE__);} @@ -1703,7 +1726,7 @@ namespace VISCOUS_3D #else - struct PyDump { PyDump(SMESH_Mesh&) {} void Finish() {} }; + struct PyDump { PyDump(SMESH_Mesh&) {} void Finish() {} void Pause() {} void Resume() {} }; #define dumpFunction(f) f #define dumpMove(n) #define dumpMoveComm(n,txt) @@ -1834,8 +1857,6 @@ bool _ViscousBuilder::MakeN2NMap( _MeshOfSolid* pm ) SMESH_ComputeErrorPtr _ViscousBuilder::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape) { - // TODO: set priority of solids during Gen::Compute() - _mesh = & theMesh; // check if proxy mesh already computed @@ -1847,6 +1868,7 @@ SMESH_ComputeErrorPtr _ViscousBuilder::Compute(SMESH_Mesh& theMesh, return SMESH_ComputeErrorPtr(); // everything already computed PyDump debugDump( theMesh ); + _pyDump = &debugDump; // TODO: ignore already computed SOLIDs if ( !findSolidsWithLayers()) @@ -1857,22 +1879,37 @@ SMESH_ComputeErrorPtr _ViscousBuilder::Compute(SMESH_Mesh& theMesh, for ( size_t i = 0; i < _sdVec.size(); ++i ) { - if ( ! makeLayer(_sdVec[i]) ) + size_t iSD = 0; + for ( iSD = 0; iSD < _sdVec.size(); ++iSD ) // find next SOLID to compute + if ( _sdVec[iSD]._before.IsEmpty() && + !_sdVec[iSD]._solid.IsNull() && + _sdVec[iSD]._n2eMap.empty() ) + break; + + if ( ! makeLayer(_sdVec[iSD]) ) // create _LayerEdge's return _error; - if ( _sdVec[i]._n2eMap.size() == 0 ) + if ( _sdVec[iSD]._n2eMap.size() == 0 ) // no layers in a SOLID + { + _sdVec[iSD]._solid.Nullify(); continue; - - if ( ! inflate(_sdVec[i]) ) + } + + if ( ! inflate(_sdVec[iSD]) ) // increase length of _LayerEdge's return _error; - if ( ! refine(_sdVec[i]) ) + if ( ! refine(_sdVec[iSD]) ) // create nodes and prisms return _error; - } - if ( !shrink() ) - return _error; - addBoundaryElements(); + if ( ! shrink(_sdVec[iSD]) ) // shrink 2D mesh on FACEs w/o layer + return _error; + + addBoundaryElements(_sdVec[iSD]); // create quadrangles on prism bare sides + + const TopoDS_Shape& solid = _sdVec[iSD]._solid; + for ( iSD = 0; iSD < _sdVec.size(); ++iSD ) + _sdVec[iSD]._before.Remove( solid ); + } makeGroupOfLE(); // debug debugDump.Finish(); @@ -1921,12 +1958,14 @@ bool _ViscousBuilder::findSolidsWithLayers() TopExp::MapShapes( _mesh->GetShapeToMesh(), TopAbs_SOLID, allSolids ); _sdVec.reserve( allSolids.Extent()); - SMESH_Gen* gen = _mesh->GetGen(); SMESH_HypoFilter filter; for ( int i = 1; i <= allSolids.Extent(); ++i ) { // find StdMeshers_ViscousLayers hyp assigned to the i-th solid - SMESH_Algo* algo = gen->GetAlgo( *_mesh, allSolids(i) ); + SMESH_subMesh* sm = _mesh->GetSubMesh( allSolids(i) ); + if ( sm->GetSubMeshDS() && sm->GetSubMeshDS()->NbElements() > 0 ) + continue; // solid is already meshed + SMESH_Algo* algo = sm->GetAlgo(); if ( !algo ) continue; // TODO: check if algo is hidden const list & allHyps = @@ -1951,6 +1990,7 @@ bool _ViscousBuilder::findSolidsWithLayers() soData->_index = getMeshDS()->ShapeToIndex( allSolids(i)); soData->_helper = new SMESH_MesherHelper( *_mesh ); soData->_helper->SetSubShape( allSolids(i) ); + _solids.Add( allSolids(i) ); } soData->_hyps.push_back( viscHyp ); soData->_hypShapes.push_back( hypShape ); @@ -1965,7 +2005,37 @@ bool _ViscousBuilder::findSolidsWithLayers() //================================================================================ /*! - * \brief + * \brief Set a _SolidData to be computed before another + */ +//================================================================================ + +bool _ViscousBuilder::setBefore( _SolidData& solidBefore, _SolidData& solidAfter ) +{ + // check possibility to set this order; get all solids before solidBefore + TopTools_IndexedMapOfShape allSolidsBefore; + allSolidsBefore.Add( solidBefore._solid ); + for ( int i = 1; i <= allSolidsBefore.Extent(); ++i ) + { + int iSD = _solids.FindIndex( allSolidsBefore(i) ); + if ( iSD ) + { + TopTools_MapIteratorOfMapOfShape soIt( _sdVec[ iSD-1 ]._before ); + for ( ; soIt.More(); soIt.Next() ) + allSolidsBefore.Add( soIt.Value() ); + } + } + if ( allSolidsBefore.Contains( solidAfter._solid )) + return false; + + for ( int i = 1; i <= allSolidsBefore.Extent(); ++i ) + solidAfter._before.Add( allSolidsBefore(i) ); + + return true; +} + +//================================================================================ +/*! + * \brief */ //================================================================================ @@ -1973,13 +2043,10 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith) { SMESH_MesherHelper helper( *_mesh ); TopExp_Explorer exp; - TopTools_IndexedMapOfShape solids; // collect all faces-to-ignore defined by hyp for ( size_t i = 0; i < _sdVec.size(); ++i ) { - solids.Add( _sdVec[i]._solid ); - // get faces-to-ignore defined by each hyp typedef const StdMeshers_ViscousLayers* THyp; typedef std::pair< set, THyp > TFacesOfHyp; @@ -2075,8 +2142,9 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith) } } - // Find faces to shrink mesh on (solution 2 in issue 0020832); + // Find FACEs to shrink mesh on (solution 2 in issue 0020832): fill in _shrinkShape2Shape TopTools_IndexedMapOfShape shapes; + std::string structAlgoName = "Hexa_3D"; for ( size_t i = 0; i < _sdVec.size(); ++i ) { shapes.Clear(); @@ -2084,121 +2152,32 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith) for ( int iE = 1; iE <= shapes.Extent(); ++iE ) { const TopoDS_Shape& edge = shapes(iE); - // find 2 faces sharing an edge + // find 2 FACEs sharing an EDGE TopoDS_Shape FF[2]; - PShapeIteratorPtr fIt = helper.GetAncestors(edge, *_mesh, TopAbs_FACE); + PShapeIteratorPtr fIt = helper.GetAncestors(edge, *_mesh, TopAbs_FACE, &_sdVec[i]._solid); while ( fIt->more()) { const TopoDS_Shape* f = fIt->next(); - if ( helper.IsSubShape( *f, _sdVec[i]._solid)) - FF[ int( !FF[0].IsNull()) ] = *f; + FF[ int( !FF[0].IsNull()) ] = *f; } if( FF[1].IsNull() ) continue; // seam edge can be shared by 1 FACE only + // check presence of layers on them int ignore[2]; for ( int j = 0; j < 2; ++j ) - ignore[j] = _sdVec[i]._ignoreFaceIds.count ( getMeshDS()->ShapeToIndex( FF[j] )); + ignore[j] = _sdVec[i]._ignoreFaceIds.count( getMeshDS()->ShapeToIndex( FF[j] )); if ( ignore[0] == ignore[1] ) continue; // nothing interesting TopoDS_Shape fWOL = FF[ ignore[0] ? 0 : 1 ]; - // check presence of layers on fWOL within an adjacent SOLID - bool collision = false; - PShapeIteratorPtr sIt = helper.GetAncestors( fWOL, *_mesh, TopAbs_SOLID ); - while ( const TopoDS_Shape* solid = sIt->next() ) - if ( !solid->IsSame( _sdVec[i]._solid )) - { - int iSolid = solids.FindIndex( *solid ); - int iFace = getMeshDS()->ShapeToIndex( fWOL ); - if ( iSolid > 0 && !_sdVec[ iSolid-1 ]._ignoreFaceIds.count( iFace )) - { - //_sdVec[i]._noShrinkShapes.insert( iFace ); - //fWOL.Nullify(); - collision = true; - } - } - // add edge to maps + + // add EDGE to maps if ( !fWOL.IsNull()) { TGeomID edgeInd = getMeshDS()->ShapeToIndex( edge ); _sdVec[i]._shrinkShape2Shape.insert( make_pair( edgeInd, fWOL )); - if ( collision ) - { - // _shrinkShape2Shape will be used to temporary inflate _LayerEdge's based - // on the edge but shrink won't be performed - _sdVec[i]._noShrinkShapes.insert( edgeInd ); - } } } } - // Exclude from _shrinkShape2Shape FACE's that can't be shrinked since - // the algo of the SOLID sharing the FACE does not support it - set< string > notSupportAlgos; notSupportAlgos.insert("Hexa_3D"); - for ( size_t i = 0; i < _sdVec.size(); ++i ) - { - map< TGeomID, TopoDS_Shape >::iterator e2f = _sdVec[i]._shrinkShape2Shape.begin(); - for ( ; e2f != _sdVec[i]._shrinkShape2Shape.end(); ++e2f ) - { - const TopoDS_Shape& fWOL = e2f->second; - const TGeomID edgeID = e2f->first; - bool notShrinkFace = false; - PShapeIteratorPtr soIt = helper.GetAncestors(fWOL, *_mesh, TopAbs_SOLID); - while ( soIt->more() ) - { - const TopoDS_Shape* solid = soIt->next(); - if ( _sdVec[i]._solid.IsSame( *solid )) continue; - SMESH_Algo* algo = _mesh->GetGen()->GetAlgo( *_mesh, *solid ); - if ( !algo || !notSupportAlgos.count( algo->GetName() )) continue; - notShrinkFace = true; - size_t iSolid = 0; - for ( ; iSolid < _sdVec.size(); ++iSolid ) - { - if ( _sdVec[iSolid]._solid.IsSame( *solid ) ) { - if ( _sdVec[iSolid]._shrinkShape2Shape.count( edgeID )) - notShrinkFace = false; - break; - } - } - if ( notShrinkFace ) - { - _sdVec[i]._noShrinkShapes.insert( edgeID ); - - // add VERTEXes of the edge in _noShrinkShapes - TopoDS_Shape edge = getMeshDS()->IndexToShape( edgeID ); - for ( TopoDS_Iterator vIt( edge ); vIt.More(); vIt.Next() ) - _sdVec[i]._noShrinkShapes.insert( getMeshDS()->ShapeToIndex( vIt.Value() )); - - // check if there is a collision with to-shrink-from EDGEs in iSolid - if ( iSolid == _sdVec.size() ) - continue; // no VL in the solid - shapes.Clear(); - TopExp::MapShapes( fWOL, TopAbs_EDGE, shapes); - for ( int iE = 1; iE <= shapes.Extent(); ++iE ) - { - const TopoDS_Edge& E = TopoDS::Edge( shapes( iE )); - const TGeomID eID = getMeshDS()->ShapeToIndex( E ); - if ( eID == edgeID || - !_sdVec[iSolid]._shrinkShape2Shape.count( eID ) || - _sdVec[i]._noShrinkShapes.count( eID )) - continue; - for ( int is1st = 0; is1st < 2; ++is1st ) - { - TopoDS_Vertex V = helper.IthVertex( is1st, E ); - if ( _sdVec[i]._noShrinkShapes.count( getMeshDS()->ShapeToIndex( V ) )) - { - // _sdVec[i]._noShrinkShapes.insert( eID ); - // V = helper.IthVertex( !is1st, E ); - // _sdVec[i]._noShrinkShapes.insert( getMeshDS()->ShapeToIndex( V )); - //iE = 0; // re-start the loop on EDGEs of fWOL - return error("No way to make a conformal mesh with " - "the given set of faces with layers", _sdVec[i]._index); - } - } - } - } - - } // while ( soIt->more() ) - } // loop on _sdVec[i]._shrinkShape2Shape - } // loop on _sdVec to fill in _SolidData::_noShrinkShapes // Find the SHAPE along which to inflate _LayerEdge based on VERTEX @@ -2212,18 +2191,14 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith) // find faces WOL sharing the vertex vector< TopoDS_Shape > facesWOL; size_t totalNbFaces = 0; - PShapeIteratorPtr fIt = helper.GetAncestors(vertex, *_mesh, TopAbs_FACE); + PShapeIteratorPtr fIt = helper.GetAncestors(vertex, *_mesh, TopAbs_FACE, &_sdVec[i]._solid ); while ( fIt->more()) { const TopoDS_Shape* f = fIt->next(); - if ( helper.IsSubShape( *f, _sdVec[i]._solid ) ) - { - totalNbFaces++; - const int fID = getMeshDS()->ShapeToIndex( *f ); - if ( _sdVec[i]._ignoreFaceIds.count ( fID ) /*&& - !_sdVec[i]._noShrinkShapes.count( fID )*/) - facesWOL.push_back( *f ); - } + totalNbFaces++; + const int fID = getMeshDS()->ShapeToIndex( *f ); + if ( _sdVec[i]._ignoreFaceIds.count ( fID ) /*&& !_sdVec[i]._noShrinkShapes.count( fID )*/) + facesWOL.push_back( *f ); } if ( facesWOL.size() == totalNbFaces || facesWOL.empty() ) continue; // no layers at this vertex or no WOL @@ -2273,7 +2248,130 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith) } } - // add FACEs of other SOLIDs to _ignoreFaceIds + // Add to _noShrinkShapes sub-shapes of FACE's that can't be shrinked since + // the algo of the SOLID sharing the FACE does not support it or for other reasons + set< string > notSupportAlgos; notSupportAlgos.insert( structAlgoName ); + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + map< TGeomID, TopoDS_Shape >::iterator e2f = _sdVec[i]._shrinkShape2Shape.begin(); + for ( ; e2f != _sdVec[i]._shrinkShape2Shape.end(); ++e2f ) + { + const TopoDS_Shape& fWOL = e2f->second; + const TGeomID edgeID = e2f->first; + TGeomID faceID = getMeshDS()->ShapeToIndex( fWOL ); + TopoDS_Shape edge = getMeshDS()->IndexToShape( edgeID ); + if ( edge.ShapeType() != TopAbs_EDGE ) + continue; // shrink shape is VERTEX + + TopoDS_Shape solid; + PShapeIteratorPtr soIt = helper.GetAncestors(fWOL, *_mesh, TopAbs_SOLID); + while ( soIt->more() && solid.IsNull() ) + { + const TopoDS_Shape* so = soIt->next(); + if ( !so->IsSame( _sdVec[i]._solid )) + solid = *so; + } + if ( solid.IsNull() ) + continue; + + bool noShrinkE = false; + SMESH_Algo* algo = _mesh->GetSubMesh( solid )->GetAlgo(); + bool isStructured = ( algo && algo->GetName() == structAlgoName ); + size_t iSolid = _solids.FindIndex( solid ) - 1; + if ( iSolid < _sdVec.size() && _sdVec[ iSolid ]._ignoreFaceIds.count( faceID )) + { + // the adjacent SOLID has NO layers on fWOL; + // shrink allowed if + // - there are layers on the EDGE in the adjacent SOLID + // - there are NO layers in the adjacent SOLID && algo is unstructured and computed later + bool hasWLAdj = (_sdVec[iSolid]._shrinkShape2Shape.count( edgeID )); + bool shrinkAllowed = (( hasWLAdj ) || + ( !isStructured && setBefore( _sdVec[ i ], _sdVec[ iSolid ] ))); + noShrinkE = !shrinkAllowed; + } + else if ( iSolid < _sdVec.size() ) + { + // the adjacent SOLID has layers on fWOL; + // check if SOLID's mesh is unstructured and then try to set it + // to be computed after the i-th solid + if ( isStructured || !setBefore( _sdVec[ i ], _sdVec[ iSolid ] )) + noShrinkE = true; // don't shrink fWOL + } + else + { + // the adjacent SOLID has NO layers at all + noShrinkE = isStructured; + } + + if ( noShrinkE ) + { + _sdVec[i]._noShrinkShapes.insert( edgeID ); + + // check if there is a collision with to-shrink-from EDGEs in iSolid + // if ( iSolid < _sdVec.size() ) + // { + // shapes.Clear(); + // TopExp::MapShapes( fWOL, TopAbs_EDGE, shapes); + // for ( int iE = 1; iE <= shapes.Extent(); ++iE ) + // { + // const TopoDS_Edge& E = TopoDS::Edge( shapes( iE )); + // const TGeomID eID = getMeshDS()->ShapeToIndex( E ); + // if ( eID == edgeID || + // !_sdVec[iSolid]._shrinkShape2Shape.count( eID ) || + // _sdVec[i]._noShrinkShapes.count( eID )) + // continue; + // for ( int is1st = 0; is1st < 2; ++is1st ) + // { + // TopoDS_Vertex V = helper.IthVertex( is1st, E ); + // if ( _sdVec[i]._noShrinkShapes.count( getMeshDS()->ShapeToIndex( V ) )) + // { + // return error("No way to make a conformal mesh with " + // "the given set of faces with layers", _sdVec[i]._index); + // } + // } + // } + // } + } + + // add VERTEXes of the edge in _noShrinkShapes, which is necessary if + // _shrinkShape2Shape is different in the adjacent SOLID + for ( TopoDS_Iterator vIt( edge ); vIt.More(); vIt.Next() ) + { + TGeomID vID = getMeshDS()->ShapeToIndex( vIt.Value() ); + bool noShrinkV = false; + + if ( iSolid < _sdVec.size() ) + { + if ( _sdVec[ iSolid ]._ignoreFaceIds.count( faceID )) + { + map< TGeomID, TopoDS_Shape >::iterator i2S, i2SAdj; + i2S = _sdVec[i ]._shrinkShape2Shape.find( vID ); + i2SAdj = _sdVec[iSolid]._shrinkShape2Shape.find( vID ); + if ( i2SAdj == _sdVec[iSolid]._shrinkShape2Shape.end() ) + noShrinkV = ( i2S->second.ShapeType() == TopAbs_EDGE || isStructured ); + else + noShrinkV = ( ! i2S->second.IsSame( i2SAdj->second )); + } + else + { + noShrinkV = noShrinkE; + } + } + else + { + // the adjacent SOLID has NO layers at all + noShrinkV = ( isStructured || + _sdVec[i]._shrinkShape2Shape[ vID ].ShapeType() == TopAbs_EDGE ); + } + if ( noShrinkV ) + _sdVec[i]._noShrinkShapes.insert( vID ); + } + + } // loop on _sdVec[i]._shrinkShape2Shape + } // loop on _sdVec to fill in _SolidData::_noShrinkShapes + + + // add FACEs of other SOLIDs to _ignoreFaceIds for ( size_t i = 0; i < _sdVec.size(); ++i ) { shapes.Clear(); @@ -2696,8 +2794,6 @@ void _ViscousBuilder::limitStepSizeByCurvature( _SolidData& data ) { SMESH_MesherHelper helper( *_mesh ); - const int nbTestPnt = 5; // on a FACE sub-shape - BRepLProp_SLProps surfProp( 2, 1e-6 ); data._convexFaces.clear(); @@ -2709,58 +2805,27 @@ void _ViscousBuilder::limitStepSizeByCurvature( _SolidData& data ) continue; TopoDS_Face F = TopoDS::Face( eof._shape ); - SMESH_subMesh * sm = eof._subMesh; const TGeomID faceID = eof._shapeID; BRepAdaptor_Surface surface( F, false ); surfProp.SetSurface( surface ); - bool isTooCurved = false; - _ConvexFace cnvFace; - const double oriFactor = ( F.Orientation() == TopAbs_REVERSED ? +1. : -1. ); - SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true); - while ( smIt->more() ) - { - sm = smIt->next(); - const TGeomID subID = sm->GetId(); - // find _LayerEdge's of a sub-shape - _EdgesOnShape* eos; - if (( eos = data.GetShapeEdges( subID ))) - cnvFace._subIdToEOS.insert( make_pair( subID, eos )); - else - continue; - // check concavity and curvature and limit data._stepSize - const double minCurvature = - 1. / ( eos->_hyp.GetTotalThickness() * ( 1 + theThickToIntersection )); - size_t iStep = Max( 1, eos->_edges.size() / nbTestPnt ); - for ( size_t i = 0; i < eos->_edges.size(); i += iStep ) - { - gp_XY uv = helper.GetNodeUV( F, eos->_edges[ i ]->_nodes[0] ); - surfProp.SetParameters( uv.X(), uv.Y() ); - if ( !surfProp.IsCurvatureDefined() ) - continue; - if ( surfProp.MaxCurvature() * oriFactor > minCurvature ) - { - limitStepSize( data, 0.9 / surfProp.MaxCurvature() * oriFactor ); - isTooCurved = true; - } - if ( surfProp.MinCurvature() * oriFactor > minCurvature ) - { - limitStepSize( data, 0.9 / surfProp.MinCurvature() * oriFactor ); - isTooCurved = true; - } - } - } // loop on sub-shapes of the FACE + cnvFace._face = F; + cnvFace._normalsFixed = false; + cnvFace._isTooCurved = false; - if ( !isTooCurved ) continue; + double maxCurvature = cnvFace.GetMaxCurvature( data, eof, surfProp, helper ); + if ( maxCurvature > 0 ) + { + limitStepSize( data, 0.9 / maxCurvature ); + findEdgesToUpdateNormalNearConvexFace( cnvFace, data, helper ); + } + if ( !cnvFace._isTooCurved ) continue; _ConvexFace & convFace = data._convexFaces.insert( make_pair( faceID, cnvFace )).first->second; - convFace._face = F; - convFace._normalsFixed = false; - // skip a closed surface (data._convexFaces is useful anyway) bool isClosedF = false; helper.SetSubShape( F ); @@ -2773,6 +2838,7 @@ void _ViscousBuilder::limitStepSizeByCurvature( _SolidData& data ) if ( isClosedF ) { // limit _LayerEdge::_maxLen on the FACE + const double oriFactor = ( F.Orientation() == TopAbs_REVERSED ? +1. : -1. ); const double minCurvature = 1. / ( eof._hyp.GetTotalThickness() * ( 1 + theThickToIntersection )); map< TGeomID, _EdgesOnShape* >::iterator id2eos = cnvFace._subIdToEOS.find( faceID ); @@ -2784,14 +2850,13 @@ void _ViscousBuilder::limitStepSizeByCurvature( _SolidData& data ) _LayerEdge* ledge = eos._edges[ i ]; gp_XY uv = helper.GetNodeUV( F, ledge->_nodes[0] ); surfProp.SetParameters( uv.X(), uv.Y() ); - if ( !surfProp.IsCurvatureDefined() ) - continue; - - if ( surfProp.MaxCurvature() * oriFactor > minCurvature ) - ledge->_maxLen = Min( ledge->_maxLen, 1. / surfProp.MaxCurvature() * oriFactor ); - - if ( surfProp.MinCurvature() * oriFactor > minCurvature ) - ledge->_maxLen = Min( ledge->_maxLen, 1. / surfProp.MinCurvature() * oriFactor ); + if ( surfProp.IsCurvatureDefined() ) + { + double curvature = Max( surfProp.MaxCurvature() * oriFactor, + surfProp.MinCurvature() * oriFactor ); + if ( curvature > minCurvature ) + ledge->_maxLen = Min( ledge->_maxLen, 1. / curvature ); + } } } continue; @@ -2872,7 +2937,7 @@ bool _ViscousBuilder::findShapesToSmooth( _SolidData& data ) //const double tgtThick = /*Min( 0.5 * data._geomSize, */data._maxThickness; // Find shapes needing smoothing; such a shape has _LayerEdge._normal on it's - // boundry inclined to the shape at a sharp angle + // boundary inclined to the shape at a sharp angle //list< TGeomID > shapesToSmooth; TopTools_MapOfShape edgesOfSmooFaces; @@ -2968,8 +3033,8 @@ bool _ViscousBuilder::findShapesToSmooth( _SolidData& data ) { eos._edgeSmoother = new _Smoother1D( curve, eos ); - for ( size_t i = 0; i < eos._edges.size(); ++i ) - eos._edges[i]->Set( _LayerEdge::TO_SMOOTH ); + // for ( size_t i = 0; i < eos._edges.size(); ++i ) + // eos._edges[i]->Set( _LayerEdge::TO_SMOOTH ); } } } @@ -3348,11 +3413,12 @@ bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, } // find _normal + bool fromVonF = false; if ( useGeometry ) { - bool fromVonF = ( eos.ShapeType() == TopAbs_VERTEX && - eos.SWOLType() == TopAbs_FACE && - totalNbFaces > 1 ); + fromVonF = ( eos.ShapeType() == TopAbs_VERTEX && + eos.SWOLType() == TopAbs_FACE && + totalNbFaces > 1 ); if ( onShrinkShape && !fromVonF ) // one of faces the node is on has no layers { @@ -3395,11 +3461,16 @@ bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, if ( nbOkNorms == 0 ) return error(SMESH_Comment("Can't get normal to node ") << node->GetID(), data._index); + if ( totalNbFaces >= 3 ) + { + edge._normal = getNormalByOffset( &edge, face2Norm, totalNbFaces, fromVonF ); + } + if ( edge._normal.Modulus() < 1e-3 && nbOkNorms > 1 ) { // opposite normals, re-get normals at shifted positions (IPAL 52426) edge._normal.SetCoord( 0,0,0 ); - for ( int iF = 0; iF < totalNbFaces; ++iF ) + for ( int iF = 0; iF < totalNbFaces - fromVonF; ++iF ) { const TopoDS_Face& F = face2Norm[iF].first; geomNorm = getFaceNormal( node, F, helper, normOK, /*shiftInside=*/true ); @@ -3410,11 +3481,6 @@ bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, edge._normal += face2Norm[ iF ].second; } } - - if ( totalNbFaces >= 3 ) - { - edge._normal = getNormalByOffset( &edge, face2Norm, totalNbFaces, fromVonF ); - } } } else // !useGeometry - get _normal using surrounding mesh faces @@ -3454,14 +3520,19 @@ bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, break; } case TopAbs_VERTEX: { - //if ( eos.SWOLType() != TopAbs_FACE ) // else _cosin is set by getFaceDir() + if ( fromVonF ) + { + getFaceDir( TopoDS::Face( eos._sWOL ), TopoDS::Vertex( eos._shape ), + node, helper, normOK, &edge._cosin ); + } + else if ( eos.SWOLType() != TopAbs_FACE ) // else _cosin is set by getFaceDir() { TopoDS_Vertex V = TopoDS::Vertex( eos._shape ); gp_Vec inFaceDir = getFaceDir( F, V, node, helper, normOK ); double angle = inFaceDir.Angle( edge._normal ); // [0,PI] edge._cosin = Cos( angle ); if ( totalNbFaces > 2 || helper.IsSeamShape( node->getshapeId() )) - for ( int iF = totalNbFaces-2; iF >=0; --iF ) + for ( int iF = 1; iF < totalNbFaces; ++iF ) { F = face2Norm[ iF ].first; inFaceDir = getFaceDir( F, V, node, helper, normOK=true ); @@ -4081,7 +4152,7 @@ void _LayerEdge::SetDataByNeighbors( const SMDS_MeshNode* n1, //================================================================================ /*! * \brief Copy data from a _LayerEdge of other SOLID and based on the same node; - * this and other _LayerEdge's are inflated along a FACE or an EDGE + * this and the other _LayerEdge are inflated along a FACE or an EDGE */ //================================================================================ @@ -4347,11 +4418,14 @@ bool _ViscousBuilder::inflate(_SolidData& data) data._epsilon = data._stepSize * 1e-7; debugMsg( "-- geomSize = " << data._geomSize << ", stepSize = " << data._stepSize ); + _pyDump->Pause(); findCollisionEdges( data, helper ); limitMaxLenByCurvature( data, helper ); + _pyDump->Resume(); + // limit length of _LayerEdge's around MULTI_NORMAL _LayerEdge's for ( size_t i = 0; i < data._edgesOnShape.size(); ++i ) if ( data._edgesOnShape[i].ShapeType() == TopAbs_VERTEX && @@ -4431,7 +4505,10 @@ bool _ViscousBuilder::inflate(_SolidData& data) const double shapeTgtThick = eos._hyp.GetTotalThickness(); for ( size_t i = 0; i < eos._edges.size(); ++i ) { - avgThick += Min( 1., eos._edges[i]->_len / shapeTgtThick ); + if ( eos._edges[i]->_nodes.size() > 1 ) + avgThick += Min( 1., eos._edges[i]->_len / shapeTgtThick ); + else + avgThick += shapeTgtThick; nbActiveEdges += ( ! eos._edges[i]->Is( _LayerEdge::BLOCKED )); } } @@ -4875,7 +4952,7 @@ bool _ViscousBuilder::smoothAndCheck(_SolidData& data, // ignore intersection of a _LayerEdge based on a _ConvexFace with a face // lying on this _ConvexFace if ( _ConvexFace* convFace = data.GetConvexFace( intFace->getshapeId() )) - if ( convFace->_subIdToEOS.count ( eos._shapeID )) + if ( convFace->_isTooCurved && convFace->_subIdToEOS.count ( eos._shapeID )) continue; // ignore intersection of a _LayerEdge based on a FACE with an element on this FACE @@ -4887,15 +4964,16 @@ bool _ViscousBuilder::smoothAndCheck(_SolidData& data, if ( dist > 0 ) { bool toIgnore = false; - if ( eos._edges[i]->Is( _LayerEdge::TO_SMOOTH )) + if ( eos._toSmooth ) { const TopoDS_Shape& S = getMeshDS()->IndexToShape( intFace->getshapeId() ); if ( !S.IsNull() && S.ShapeType() == TopAbs_FACE ) { - TopExp_Explorer edge( eos._shape, TopAbs_EDGE ); - for ( ; !toIgnore && edge.More(); edge.Next() ) - // is adjacent - has a common EDGE - toIgnore = ( helper.IsSubShape( edge.Current(), S )); + TopExp_Explorer sub( eos._shape, + eos.ShapeType() == TopAbs_FACE ? TopAbs_EDGE : TopAbs_VERTEX ); + for ( ; !toIgnore && sub.More(); sub.Next() ) + // is adjacent - has a common EDGE or VERTEX + toIgnore = ( helper.IsSubShape( sub.Current(), S )); if ( toIgnore ) // check angle between normals { @@ -5180,7 +5258,7 @@ void _ViscousBuilder::putOnOffsetSurface( _EdgesOnShape& eos, int infStep, vector< _EdgesOnShape* >& eosC1, int smooStep, - bool moveAll ) + int moveAll ) { _EdgesOnShape * eof = & eos; if ( eos.ShapeType() != TopAbs_FACE ) // eos is a boundary of C1 FACE, look for the FACE eos @@ -5211,8 +5289,13 @@ void _ViscousBuilder::putOnOffsetSurface( _EdgesOnShape& eos, edge->Unset( _LayerEdge::MARKED ); if ( edge->Is( _LayerEdge::BLOCKED ) || !edge->_curvature ) continue; - if ( !moveAll && !edge->Is( _LayerEdge::MOVED )) + if ( moveAll == _LayerEdge::UPD_NORMAL_CONV ) + { + if ( !edge->Is( _LayerEdge::UPD_NORMAL_CONV )) continue; + } + else if ( !moveAll && !edge->Is( _LayerEdge::MOVED )) + continue; int nbBlockedAround = 0; for ( size_t iN = 0; iN < edge->_neibors.size(); ++iN ) @@ -5222,7 +5305,7 @@ void _ViscousBuilder::putOnOffsetSurface( _EdgesOnShape& eos, gp_Pnt tgtP = SMESH_TNodeXYZ( edge->_nodes.back() ); gp_Pnt2d uv = eof->_offsetSurf->NextValueOfUV( edge->_curvature->_uv, tgtP, preci ); - if ( eof->_offsetSurf->Gap() > edge->_len ) continue; // NextValueOfUV() bug + if ( eof->_offsetSurf->Gap() > edge->_len ) continue; // NextValueOfUV() bug edge->_curvature->_uv = uv; if ( eof->_offsetSurf->Gap() < 10 * preci ) continue; // same pos @@ -5241,9 +5324,15 @@ void _ViscousBuilder::putOnOffsetSurface( _EdgesOnShape& eos, edge->_pos.back() = newP; edge->Set( _LayerEdge::MARKED ); + if ( moveAll == _LayerEdge::UPD_NORMAL_CONV ) + { + edge->_normal = ( newP - prevP ).Normalized(); + } } } + + #ifdef _DEBUG_ // dumpMove() for debug size_t i = 0; @@ -5252,7 +5341,7 @@ void _ViscousBuilder::putOnOffsetSurface( _EdgesOnShape& eos, break; if ( i < eos._edges.size() ) { - dumpFunction(SMESH_Comment("putOnOffsetSurface_F") << eos._shapeID + dumpFunction(SMESH_Comment("putOnOffsetSurface_S") << eos._shapeID << "_InfStep" << infStep << "_" << smooStep ); for ( ; i < eos._edges.size(); ++i ) { @@ -5262,6 +5351,26 @@ void _ViscousBuilder::putOnOffsetSurface( _EdgesOnShape& eos, dumpFunctionEnd(); } #endif + + _ConvexFace* cnvFace; + if ( moveAll != _LayerEdge::UPD_NORMAL_CONV && + eos.ShapeType() == TopAbs_FACE && + (cnvFace = eos.GetData().GetConvexFace( eos._shapeID )) && + !cnvFace->_normalsFixedOnBorders ) + { + // put on the surface nodes built on FACE boundaries + SMESH_subMeshIteratorPtr smIt = eos._subMesh->getDependsOnIterator(/*includeSelf=*/false); + while ( smIt->more() ) + { + SMESH_subMesh* sm = smIt->next(); + _EdgesOnShape* subEOS = eos.GetData().GetShapeEdges( sm->GetId() ); + if ( !subEOS->_sWOL.IsNull() ) continue; + if ( std::find( eosC1.begin(), eosC1.end(), subEOS ) != eosC1.end() ) continue; + + putOnOffsetSurface( *subEOS, infStep, eosC1, smooStep, _LayerEdge::UPD_NORMAL_CONV ); + } + cnvFace->_normalsFixedOnBorders = true; + } } //================================================================================ @@ -5359,6 +5468,106 @@ Handle(Geom_Curve) _Smoother1D::CurveForSmooth( const TopoDS_Edge& E, return Handle(Geom_Curve)(); } +//================================================================================ +/*! + * \brief Smooth edges on EDGE + */ +//================================================================================ + +bool _Smoother1D::Perform(_SolidData& data, + Handle(ShapeAnalysis_Surface)& surface, + const TopoDS_Face& F, + SMESH_MesherHelper& helper ) +{ + if ( _leParams.empty() || ( !isAnalytic() && _offPoints.empty() )) + prepare( data ); + + findEdgesToSmooth(); + if ( isAnalytic() ) + return smoothAnalyticEdge( data, surface, F, helper ); + else + return smoothComplexEdge ( data, surface, F, helper ); +} + +//================================================================================ +/*! + * \brief Find edges to smooth + */ +//================================================================================ + +void _Smoother1D::findEdgesToSmooth() +{ + _LayerEdge* leOnV[2] = { getLEdgeOnV(0), getLEdgeOnV(1) }; + for ( int iEnd = 0; iEnd < 2; ++iEnd ) + if ( leOnV[iEnd]->Is( _LayerEdge::NORMAL_UPDATED )) + _leOnV[iEnd]._cosin = Abs( _edgeDir[iEnd].Normalized() * leOnV[iEnd]->_normal ); + + _eToSmooth[0].first = _eToSmooth[0].second = 0; + + for ( size_t i = 0; i < _eos.size(); ++i ) + { + if ( !_eos[i]->Is( _LayerEdge::TO_SMOOTH )) + { + if ( needSmoothing( _leOnV[0]._cosin, _eos[i]->_len, _curveLen * _leParams[i] ) || + isToSmooth( i )) + _eos[i]->Set( _LayerEdge::TO_SMOOTH ); + else + break; + } + _eToSmooth[0].second = i+1; + } + + _eToSmooth[1].first = _eToSmooth[1].second = _eos.size(); + + for ( int i = _eos.size() - 1; i >= _eToSmooth[0].second; --i ) + { + if ( !_eos[i]->Is( _LayerEdge::TO_SMOOTH )) + { + if ( needSmoothing( _leOnV[1]._cosin, _eos[i]->_len, _curveLen * ( 1.-_leParams[i] )) || + isToSmooth( i )) + _eos[i]->Set( _LayerEdge::TO_SMOOTH ); + else + break; + } + _eToSmooth[1].first = i; + } +} + +//================================================================================ +/*! + * \brief Check if iE-th _LayerEdge needs smoothing + */ +//================================================================================ + +bool _Smoother1D::isToSmooth( int iE ) +{ + SMESH_NodeXYZ pi( _eos[iE]->_nodes[0] ); + SMESH_NodeXYZ p0( _eos[iE]->_2neibors->srcNode(0) ); + SMESH_NodeXYZ p1( _eos[iE]->_2neibors->srcNode(1) ); + gp_XYZ seg0 = pi - p0; + gp_XYZ seg1 = p1 - pi; + gp_XYZ tangent = seg0 + seg1; + double tangentLen = tangent.Modulus(); + double segMinLen = Min( seg0.Modulus(), seg1.Modulus() ); + if ( tangentLen < std::numeric_limits::min() ) + return false; + tangent /= tangentLen; + + for ( size_t i = 0; i < _eos[iE]->_neibors.size(); ++i ) + { + _LayerEdge* ne = _eos[iE]->_neibors[i]; + if ( !ne->Is( _LayerEdge::TO_SMOOTH ) || + ne->_nodes.size() < 2 || + ne->_nodes[0]->GetPosition()->GetDim() != 2 ) + continue; + gp_XYZ edgeVec = SMESH_NodeXYZ( ne->_nodes.back() ) - SMESH_NodeXYZ( ne->_nodes[0] ); + double proj = edgeVec * tangent; + if ( needSmoothing( 1., proj, segMinLen )) + return true; + } + return false; +} + //================================================================================ /*! * \brief smooth _LayerEdge's on a staight EDGE or circular EDGE @@ -5372,80 +5581,100 @@ bool _Smoother1D::smoothAnalyticEdge( _SolidData& data, { if ( !isAnalytic() ) return false; - const size_t iFrom = 0, iTo = _eos._edges.size(); + size_t iFrom = 0, iTo = _eos._edges.size(); if ( _anaCurve->IsKind( STANDARD_TYPE( Geom_Line ))) { if ( F.IsNull() ) // 3D { - SMESH_TNodeXYZ p0 ( _eos._edges[iFrom]->_2neibors->tgtNode(0) ); - SMESH_TNodeXYZ p1 ( _eos._edges[iTo-1]->_2neibors->tgtNode(1) ); SMESH_TNodeXYZ pSrc0( _eos._edges[iFrom]->_2neibors->srcNode(0) ); SMESH_TNodeXYZ pSrc1( _eos._edges[iTo-1]->_2neibors->srcNode(1) ); - gp_XYZ newPos, lineDir = pSrc1 - pSrc0; - _LayerEdge* vLE0 = _eos._edges[iFrom]->_2neibors->_edges[0]; - _LayerEdge* vLE1 = _eos._edges[iTo-1]->_2neibors->_edges[1]; - bool shiftOnly = ( vLE0->Is( _LayerEdge::NORMAL_UPDATED ) || - vLE0->Is( _LayerEdge::BLOCKED ) || - vLE1->Is( _LayerEdge::NORMAL_UPDATED ) || - vLE1->Is( _LayerEdge::BLOCKED )); - for ( size_t i = iFrom; i < iTo; ++i ) - { - _LayerEdge* edge = _eos._edges[i]; - SMDS_MeshNode* tgtNode = const_cast( edge->_nodes.back() ); - newPos = p0 * ( 1. - _leParams[i] ) + p1 * _leParams[i]; - - if ( shiftOnly || edge->Is( _LayerEdge::NORMAL_UPDATED )) - { - gp_XYZ curPos = SMESH_TNodeXYZ ( tgtNode ); - double shift = ( lineDir * ( newPos - pSrc0 ) - - lineDir * ( curPos - pSrc0 )); - newPos = curPos + lineDir * shift / lineDir.SquareModulus(); - } - if ( edge->Is( _LayerEdge::BLOCKED )) + //const gp_XYZ lineDir = pSrc1 - pSrc0; + //_LayerEdge* vLE0 = getLEdgeOnV( 0 ); + //_LayerEdge* vLE1 = getLEdgeOnV( 1 ); + // bool shiftOnly = ( vLE0->Is( _LayerEdge::NORMAL_UPDATED ) || + // vLE0->Is( _LayerEdge::BLOCKED ) || + // vLE1->Is( _LayerEdge::NORMAL_UPDATED ) || + // vLE1->Is( _LayerEdge::BLOCKED )); + for ( int iEnd = 0; iEnd < 2; ++iEnd ) + { + iFrom = _eToSmooth[ iEnd ].first, iTo = _eToSmooth[ iEnd ].second; + if ( iFrom >= iTo ) continue; + SMESH_TNodeXYZ p0( _eos[iFrom]->_2neibors->tgtNode(0) ); + SMESH_TNodeXYZ p1( _eos[iTo-1]->_2neibors->tgtNode(1) ); + double param0 = ( iFrom == 0 ) ? 0. : _leParams[ iFrom-1 ]; + double param1 = _leParams[ iTo ]; + for ( size_t i = iFrom; i < iTo; ++i ) { - SMESH_TNodeXYZ pSrc( edge->_nodes[0] ); - double curThick = pSrc.SquareDistance( tgtNode ); - double newThink = ( pSrc - newPos ).SquareModulus(); - if ( newThink > curThick ) - continue; + _LayerEdge* edge = _eos[i]; + SMDS_MeshNode* tgtNode = const_cast( edge->_nodes.back() ); + double param = ( _leParams[i] - param0 ) / ( param1 - param0 ); + gp_XYZ newPos = p0 * ( 1. - param ) + p1 * param; + + // if ( shiftOnly || edge->Is( _LayerEdge::NORMAL_UPDATED )) + // { + // gp_XYZ curPos = SMESH_TNodeXYZ ( tgtNode ); + // double shift = ( lineDir * ( newPos - pSrc0 ) - + // lineDir * ( curPos - pSrc0 )); + // newPos = curPos + lineDir * shift / lineDir.SquareModulus(); + // } + if ( edge->Is( _LayerEdge::BLOCKED )) + { + SMESH_TNodeXYZ pSrc( edge->_nodes[0] ); + double curThick = pSrc.SquareDistance( tgtNode ); + double newThink = ( pSrc - newPos ).SquareModulus(); + if ( newThink > curThick ) + continue; + } + edge->_pos.back() = newPos; + tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() ); + dumpMove( tgtNode ); } - edge->_pos.back() = newPos; - tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() ); - dumpMove( tgtNode ); } } else // 2D { - _LayerEdge* e0 = getLEdgeOnV( 0 ); - _LayerEdge* e1 = getLEdgeOnV( 1 ); - gp_XY uv0 = e0->LastUV( F, *data.GetShapeEdges( e0 )); - gp_XY uv1 = e1->LastUV( F, *data.GetShapeEdges( e1 )); - if ( e0->_nodes.back() == e1->_nodes.back() ) // closed edge + _LayerEdge* eV0 = getLEdgeOnV( 0 ); + _LayerEdge* eV1 = getLEdgeOnV( 1 ); + gp_XY uvV0 = eV0->LastUV( F, *data.GetShapeEdges( eV0 )); + gp_XY uvV1 = eV1->LastUV( F, *data.GetShapeEdges( eV1 )); + if ( eV0->_nodes.back() == eV1->_nodes.back() ) // closed edge { int iPeriodic = helper.GetPeriodicIndex(); if ( iPeriodic == 1 || iPeriodic == 2 ) { - uv1.SetCoord( iPeriodic, helper.GetOtherParam( uv1.Coord( iPeriodic ))); - if ( uv0.Coord( iPeriodic ) > uv1.Coord( iPeriodic )) - std::swap( uv0, uv1 ); + uvV1.SetCoord( iPeriodic, helper.GetOtherParam( uvV1.Coord( iPeriodic ))); + if ( uvV0.Coord( iPeriodic ) > uvV1.Coord( iPeriodic )) + std::swap( uvV0, uvV1 ); } } - const gp_XY rangeUV = uv1 - uv0; - for ( size_t i = iFrom; i < iTo; ++i ) - { - if ( _eos._edges[i]->Is( _LayerEdge::BLOCKED )) continue; - gp_XY newUV = uv0 + _leParams[i] * rangeUV; - _eos._edges[i]->_pos.back().SetCoord( newUV.X(), newUV.Y(), 0 ); - - gp_Pnt newPos = surface->Value( newUV.X(), newUV.Y() ); - SMDS_MeshNode* tgtNode = const_cast( _eos._edges[i]->_nodes.back() ); - tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() ); - dumpMove( tgtNode ); + for ( int iEnd = 0; iEnd < 2; ++iEnd ) + { + iFrom = _eToSmooth[ iEnd ].first, iTo = _eToSmooth[ iEnd ].second; + if ( iFrom >= iTo ) continue; + _LayerEdge* e0 = _eos[iFrom]->_2neibors->_edges[0]; + _LayerEdge* e1 = _eos[iTo-1]->_2neibors->_edges[1]; + gp_XY uv0 = ( e0 == eV0 ) ? uvV0 : e0->LastUV( F, _eos ); + gp_XY uv1 = ( e1 == eV1 ) ? uvV1 : e1->LastUV( F, _eos ); + double param0 = ( iFrom == 0 ) ? 0. : _leParams[ iFrom-1 ]; + double param1 = _leParams[ iTo ]; + const gp_XY rangeUV = uv1 - uv0; + for ( size_t i = iFrom; i < iTo; ++i ) + { + if ( _eos[i]->Is( _LayerEdge::BLOCKED )) continue; + double param = ( _leParams[i] - param0 ) / ( param1 - param0 ); + gp_XY newUV = uv0 + param * rangeUV; + _eos[i]->_pos.back().SetCoord( newUV.X(), newUV.Y(), 0 ); + + gp_Pnt newPos = surface->Value( newUV.X(), newUV.Y() ); + SMDS_MeshNode* tgtNode = const_cast( _eos[i]->_nodes.back() ); + tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() ); + dumpMove( tgtNode ); - SMDS_FacePosition* pos = static_cast( tgtNode->GetPosition() ); - pos->SetUParameter( newUV.X() ); - pos->SetVParameter( newUV.Y() ); + SMDS_FacePosition* pos = static_cast( tgtNode->GetPosition() ); + pos->SetUParameter( newUV.X() ); + pos->SetVParameter( newUV.Y() ); + } } } return true; @@ -5484,9 +5713,10 @@ bool _Smoother1D::smoothAnalyticEdge( _SolidData& data, if ( uLast < 0 ) uLast += 2 * M_PI; - for ( size_t i = iFrom; i < iTo; ++i ) + for ( size_t i = 0; i < _eos.size(); ++i ) { - if ( _eos._edges[i]->Is( _LayerEdge::BLOCKED )) continue; + if ( _eos[i]->Is( _LayerEdge::BLOCKED )) continue; + //if ( !_eos[i]->Is( _LayerEdge::TO_SMOOTH )) continue; double u = uLast * _leParams[i]; gp_Pnt p = ElCLib::Value( u, newCirc ); _eos._edges[i]->_pos.back() = p.XYZ(); @@ -5518,9 +5748,10 @@ bool _Smoother1D::smoothAnalyticEdge( _SolidData& data, gp_Ax2d axis( center, vec0 ); gp_Circ2d circ( axis, radius ); - for ( size_t i = iFrom; i < iTo; ++i ) + for ( size_t i = 0; i < _eos.size(); ++i ) { - if ( _eos._edges[i]->Is( _LayerEdge::BLOCKED )) continue; + if ( _eos[i]->Is( _LayerEdge::BLOCKED )) continue; + //if ( !_eos[i]->Is( _LayerEdge::TO_SMOOTH )) continue; double newU = uLast * _leParams[i]; gp_Pnt2d newUV = ElCLib::Value( newU, circ ); _eos._edges[i]->_pos.back().SetCoord( newUV.X(), newUV.Y(), 0 ); @@ -5555,7 +5786,9 @@ bool _Smoother1D::smoothComplexEdge( _SolidData& data, if ( _offPoints.empty() ) return false; + // ---------------------------------------------- // move _offPoints along normals of _LayerEdge's + // ---------------------------------------------- _LayerEdge* e[2] = { getLEdgeOnV(0), getLEdgeOnV(1) }; if ( e[0]->Is( _LayerEdge::NORMAL_UPDATED )) @@ -5599,7 +5832,9 @@ bool _Smoother1D::smoothComplexEdge( _SolidData& data, } } + // ----------------------------------------------------------------- // project tgt nodes of extreme _LayerEdge's to the offset segments + // ----------------------------------------------------------------- if ( e[0]->Is( _LayerEdge::NORMAL_UPDATED )) _iSeg[0] = 0; if ( e[1]->Is( _LayerEdge::NORMAL_UPDATED )) _iSeg[1] = _offPoints.size()-2; @@ -5653,20 +5888,32 @@ bool _Smoother1D::smoothComplexEdge( _SolidData& data, return false; } + // adjust length of extreme LE (test viscous_layers_01/B7) + gp_Vec vDiv0( pExtreme[0], pProj[0] ); + gp_Vec vDiv1( pExtreme[1], pProj[1] ); + double d0 = vDiv0.Magnitude(); + double d1 = vDiv1.Magnitude(); + if ( e[0]->_normal * vDiv0.XYZ() < 0 ) e[0]->_len += d0; + else e[0]->_len -= d0; + if ( e[1]->_normal * vDiv1.XYZ() < 0 ) e[1]->_len += d1; + else e[1]->_len -= d1; + + // --------------------------------------------------------------------------------- // compute normalized length of the offset segments located between the projections + // --------------------------------------------------------------------------------- size_t iSeg = 0, nbSeg = _iSeg[1] - _iSeg[0] + 1; vector< double > len( nbSeg + 1 ); len[ iSeg++ ] = 0; - len[ iSeg++ ] = pProj[ 0 ].Distance( _offPoints[ _iSeg[0]+1 ]._xyz ); + len[ iSeg++ ] = pProj[ 0 ].Distance( _offPoints[ _iSeg[0]+1 ]._xyz )/* * e[0]->_lenFactor*/; for ( size_t i = _iSeg[0]+1; i <= _iSeg[1]; ++i, ++iSeg ) { len[ iSeg ] = len[ iSeg-1 ] + _offPoints[i].Distance( _offPoints[i+1] ); } - len[ nbSeg ] -= pProj[ 1 ].Distance( _offPoints[ _iSeg[1]+1 ]._xyz ); + len[ nbSeg ] -= pProj[ 1 ].Distance( _offPoints[ _iSeg[1]+1 ]._xyz )/* * e[1]->_lenFactor*/; - double d0 = pProj[0].Distance( pExtreme[0]); - double d1 = pProj[1].Distance( pExtreme[1]); + // d0 *= e[0]->_lenFactor; + // d1 *= e[1]->_lenFactor; double fullLen = len.back() - d0 - d1; for ( iSeg = 0; iSeg < len.size(); ++iSeg ) len[iSeg] = ( len[iSeg] - d0 ) / fullLen; @@ -5677,12 +5924,15 @@ bool _Smoother1D::smoothComplexEdge( _SolidData& data, _offPoints[ _iSeg[0] ]._xyz = pExtreme[0].XYZ(); _offPoints[ _iSeg[1]+ 1]._xyz = pExtreme[1].XYZ(); + // ------------------------------------------------------------- // distribute tgt nodes of _LayerEdge's between the projections + // ------------------------------------------------------------- iSeg = 0; - for ( size_t i = 0; i < _eos._edges.size(); ++i ) + for ( size_t i = 0; i < _eos.size(); ++i ) { - if ( _eos._edges[i]->Is( _LayerEdge::BLOCKED )) continue; + if ( _eos[i]->Is( _LayerEdge::BLOCKED )) continue; + //if ( !_eos[i]->Is( _LayerEdge::TO_SMOOTH )) continue; while ( iSeg+2 < len.size() && _leParams[i] > len[ iSeg+1 ] ) iSeg++; double r = ( _leParams[i] - len[ iSeg ]) / ( len[ iSeg+1 ] - len[ iSeg ]); @@ -5691,17 +5941,17 @@ bool _Smoother1D::smoothComplexEdge( _SolidData& data, if ( surface.IsNull() ) { - _eos._edges[i]->_pos.back() = p; + _eos[i]->_pos.back() = p; } else // project a new node position to a FACE { - gp_Pnt2d uv ( _eos._edges[i]->_pos.back().X(), _eos._edges[i]->_pos.back().Y() ); + gp_Pnt2d uv ( _eos[i]->_pos.back().X(), _eos[i]->_pos.back().Y() ); gp_Pnt2d uv2( surface->NextValueOfUV( uv, p, fTol )); p = surface->Value( uv2 ).XYZ(); - _eos._edges[i]->_pos.back().SetCoord( uv2.X(), uv2.Y(), 0 ); + _eos[i]->_pos.back().SetCoord( uv2.X(), uv2.Y(), 0 ); } - SMDS_MeshNode* tgtNode = const_cast( _eos._edges[i]->_nodes.back() ); + SMDS_MeshNode* tgtNode = const_cast( _eos[i]->_nodes.back() ); tgtNode->setXYZ( p.X(), p.Y(), p.Z() ); dumpMove( tgtNode ); } @@ -5742,8 +5992,20 @@ void _Smoother1D::prepare(_SolidData& data) double fullLen = _leParams.back() + pPrev.Distance( SMESH_TNodeXYZ( getLEdgeOnV(1)->_nodes[0])); for ( size_t i = 0; i < _leParams.size()-1; ++i ) _leParams[i] = _leParams[i+1] / fullLen; + _leParams.back() = 1.; } + _LayerEdge* leOnV[2] = { getLEdgeOnV(0), getLEdgeOnV(1) }; + + // get cosin to use in findEdgesToSmooth() + _edgeDir[0] = getEdgeDir( E, leOnV[0]->_nodes[0], data.GetHelper() ); + _edgeDir[1] = getEdgeDir( E, leOnV[1]->_nodes[0], data.GetHelper() ); + _leOnV[0]._cosin = Abs( leOnV[0]->_cosin ); + _leOnV[1]._cosin = Abs( leOnV[1]->_cosin ); + if ( _eos._sWOL.IsNull() ) // 3D + for ( int iEnd = 0; iEnd < 2; ++iEnd ) + _leOnV[iEnd]._cosin = Abs( _edgeDir[iEnd].Normalized() * leOnV[iEnd]->_normal ); + if ( isAnalytic() ) return; @@ -5770,8 +6032,6 @@ void _Smoother1D::prepare(_SolidData& data) _offPoints[i]._param = GCPnts_AbscissaPoint::Length( c3dAdaptor, u0, u ) / _curveLen; } - _LayerEdge* leOnV[2] = { getLEdgeOnV(0), getLEdgeOnV(1) }; - // set _2edges _offPoints [0]._2edges.set( &_leOnV[0], &_leOnV[0], 0.5, 0.5 ); _offPoints.back()._2edges.set( &_leOnV[1], &_leOnV[1], 0.5, 0.5 ); @@ -5809,9 +6069,6 @@ void _Smoother1D::prepare(_SolidData& data) int iLBO = _offPoints.size() - 2; // last but one - _edgeDir[0] = getEdgeDir( E, leOnV[0]->_nodes[0], data.GetHelper() ); - _edgeDir[1] = getEdgeDir( E, leOnV[1]->_nodes[0], data.GetHelper() ); - _leOnV[ 0 ]._normal = getNormalNormal( leOnV[0]->_normal, _edgeDir[0] ); _leOnV[ 1 ]._normal = getNormalNormal( leOnV[1]->_normal, _edgeDir[1] ); _leOnV[ 0 ]._len = 0; @@ -6396,6 +6653,80 @@ void _ViscousBuilder::findCollisionEdges( _SolidData& data, SMESH_MesherHelper& } } +//================================================================================ +/*! + * \brief Find _LayerEdge's located on boundary of a convex FACE whose normal + * will be updated at each inflation step + */ +//================================================================================ + +void _ViscousBuilder::findEdgesToUpdateNormalNearConvexFace( _ConvexFace & convFace, + _SolidData& data, + SMESH_MesherHelper& helper ) +{ + const TGeomID convFaceID = getMeshDS()->ShapeToIndex( convFace._face ); + const double preci = BRep_Tool::Tolerance( convFace._face ); + Handle(ShapeAnalysis_Surface) surface = helper.GetSurface( convFace._face ); + + bool edgesToUpdateFound = false; + + map< TGeomID, _EdgesOnShape* >::iterator id2eos = convFace._subIdToEOS.begin(); + for ( ; id2eos != convFace._subIdToEOS.end(); ++id2eos ) + { + _EdgesOnShape& eos = * id2eos->second; + if ( !eos._sWOL.IsNull() ) continue; + if ( !eos._hyp.ToSmooth() ) continue; + for ( size_t i = 0; i < eos._edges.size(); ++i ) + { + _LayerEdge* ledge = eos._edges[ i ]; + if ( ledge->Is( _LayerEdge::UPD_NORMAL_CONV )) continue; // already checked + if ( ledge->Is( _LayerEdge::MULTI_NORMAL )) continue; // not inflatable + + gp_XYZ tgtPos = ( SMESH_NodeXYZ( ledge->_nodes[0] ) + + ledge->_normal * ledge->_lenFactor * ledge->_maxLen ); + + // the normal must be updated if distance from tgtPos to surface is less than + // target thickness + + // find an initial UV for search of a projection of tgtPos to surface + const SMDS_MeshNode* nodeInFace = 0; + SMDS_ElemIteratorPtr fIt = ledge->_nodes[0]->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() && !nodeInFace ) + { + const SMDS_MeshElement* f = fIt->next(); + if ( convFaceID != f->getshapeId() ) continue; + + SMDS_ElemIteratorPtr nIt = f->nodesIterator(); + while ( nIt->more() && !nodeInFace ) + { + const SMDS_MeshElement* n = nIt->next(); + if ( n->getshapeId() == convFaceID ) + nodeInFace = static_cast< const SMDS_MeshNode* >( n ); + } + } + if ( !nodeInFace ) + continue; + gp_XY uv = helper.GetNodeUV( convFace._face, nodeInFace ); + + // projection + surface->NextValueOfUV( uv, tgtPos, preci ); + double dist = surface->Gap(); + if ( dist < 0.95 * ledge->_maxLen ) + { + ledge->Set( _LayerEdge::UPD_NORMAL_CONV ); + if ( !ledge->_curvature ) ledge->_curvature = new _Curvature; + ledge->_curvature->_uv.SetCoord( uv.X(), uv.Y() ); + edgesToUpdateFound = true; + } + } + } + + if ( !convFace._isTooCurved && edgesToUpdateFound ) + { + data._convexFaces.insert( make_pair( convFaceID, convFace )).first->second; + } +} + //================================================================================ /*! * \brief Modify normals of _LayerEdge's on EDGE's to avoid intersection with @@ -6595,11 +6926,9 @@ bool _ViscousBuilder::updateNormals( _SolidData& data, else // edge inflates along a FACE { TopoDS_Shape V = helper.GetSubShapeByNode( edge->_nodes[0], getMeshDS() ); - PShapeIteratorPtr eIt = helper.GetAncestors( V, *_mesh, TopAbs_EDGE ); + PShapeIteratorPtr eIt = helper.GetAncestors( V, *_mesh, TopAbs_EDGE, &eos->_sWOL ); while ( const TopoDS_Shape* E = eIt->next() ) { - if ( !helper.IsSubShape( *E, /*FACE=*/eos->_sWOL )) - continue; gp_Vec edgeDir = getEdgeDir( TopoDS::Edge( *E ), TopoDS::Vertex( V )); double angle = edgeDir.Angle( newEdge._normal ); // [0,PI] if ( angle < M_PI / 2 ) @@ -6850,6 +7179,8 @@ bool _ViscousBuilder::updateNormalsOfConvexFaces( _SolidData& data, for ( ; id2face != data._convexFaces.end(); ++id2face ) { _ConvexFace & convFace = (*id2face).second; + convFace._normalsFixedOnBorders = false; // to update at each inflation step + if ( convFace._normalsFixed ) continue; // already fixed if ( convFace.CheckPrisms() ) @@ -7212,6 +7543,59 @@ bool _ViscousBuilder::updateNormalsOfConvexFaces( _SolidData& data, return true; } +//================================================================================ +/*! + * \brief Return max curvature of a FACE + */ +//================================================================================ + +double _ConvexFace::GetMaxCurvature( _SolidData& data, + _EdgesOnShape& eof, + BRepLProp_SLProps& surfProp, + SMESH_MesherHelper& helper) +{ + double maxCurvature = 0; + + TopoDS_Face F = TopoDS::Face( eof._shape ); + + const int nbTestPnt = 5; + const double oriFactor = ( F.Orientation() == TopAbs_REVERSED ? +1. : -1. ); + SMESH_subMeshIteratorPtr smIt = eof._subMesh->getDependsOnIterator(/*includeSelf=*/true); + while ( smIt->more() ) + { + SMESH_subMesh* sm = smIt->next(); + const TGeomID subID = sm->GetId(); + + // find _LayerEdge's of a sub-shape + _EdgesOnShape* eos; + if (( eos = data.GetShapeEdges( subID ))) + this->_subIdToEOS.insert( make_pair( subID, eos )); + else + continue; + + // check concavity and curvature and limit data._stepSize + const double minCurvature = + 1. / ( eos->_hyp.GetTotalThickness() * ( 1 + theThickToIntersection )); + size_t iStep = Max( 1, eos->_edges.size() / nbTestPnt ); + for ( size_t i = 0; i < eos->_edges.size(); i += iStep ) + { + gp_XY uv = helper.GetNodeUV( F, eos->_edges[ i ]->_nodes[0] ); + surfProp.SetParameters( uv.X(), uv.Y() ); + if ( surfProp.IsCurvatureDefined() ) + { + double curvature = Max( surfProp.MaxCurvature() * oriFactor, + surfProp.MinCurvature() * oriFactor ); + maxCurvature = Max( maxCurvature, curvature ); + + if ( curvature > minCurvature ) + this->_isTooCurved = true; + } + } + } // loop on sub-shapes of the FACE + + return maxCurvature; +} + //================================================================================ /*! * \brief Finds a center of curvature of a surface at a _LayerEdge @@ -7494,13 +7878,14 @@ gp_Ax1 _LayerEdge::LastSegment(double& segLen, _EdgesOnShape& eos) const //================================================================================ /*! - * \brief Return the last position of the target node on a FACE. + * \brief Return the last (or \a which) position of the target node on a FACE. * \param [in] F - the FACE this _LayerEdge is inflated along + * \param [in] which - index of position * \return gp_XY - result UV */ //================================================================================ -gp_XY _LayerEdge::LastUV( const TopoDS_Face& F, _EdgesOnShape& eos ) const +gp_XY _LayerEdge::LastUV( const TopoDS_Face& F, _EdgesOnShape& eos, int which ) const { if ( F.IsSame( eos._sWOL )) // F is my FACE return gp_XY( _pos.back().X(), _pos.back().Y() ); @@ -7509,7 +7894,7 @@ gp_XY _LayerEdge::LastUV( const TopoDS_Face& F, _EdgesOnShape& eos ) const return gp_XY( 1e100, 1e100 ); // _sWOL is EDGE of F; _pos.back().X() is the last U on the EDGE - double f, l, u = _pos.back().X(); + double f, l, u = _pos[ which < 0 ? _pos.size()-1 : which ].X(); Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( TopoDS::Edge(eos._sWOL), F, f,l); if ( !C2d.IsNull() && f <= u && u <= l ) return C2d->Value( u ).XY(); @@ -7536,7 +7921,7 @@ bool _LayerEdge::SegTriaInter( const gp_Ax1& lastSegment, const gp_Dir& dir = lastSegment.Direction(); /* calculate distance from vert0 to ray origin */ - gp_XYZ tvec = orig.XYZ() - vert0; + //gp_XYZ tvec = orig.XYZ() - vert0; //if ( tvec * dir > EPSILON ) // intersected face is at back side of the temporary face this _LayerEdge belongs to @@ -7555,6 +7940,9 @@ bool _LayerEdge::SegTriaInter( const gp_Ax1& lastSegment, if ( det > -ANGL_EPSILON && det < ANGL_EPSILON ) return false; + /* calculate distance from vert0 to ray origin */ + gp_XYZ tvec = orig.XYZ() - vert0; + /* calculate U parameter and test bounds */ double u = ( tvec * pvec ) / det; //if (u < 0.0 || u > 1.0) @@ -7584,7 +7972,7 @@ bool _LayerEdge::SegTriaInter( const gp_Ax1& lastSegment, * \param [in] eov - EOS of the VERTEX * \param [in] eos - EOS of the FACE * \param [in] step - inflation step - * \param [in,out] badSmooEdges - not untangled _LayerEdge's + * \param [in,out] badSmooEdges - tangled _LayerEdge's */ //================================================================================ @@ -8420,7 +8808,7 @@ gp_XYZ _LayerEdge::smoothNefPolygon() { gp_XYZ newPos(0,0,0); - // get a plane to seach a solution on + // get a plane to search a solution on vector< gp_XYZ > vecs( _simplices.size() + 1 ); size_t i; @@ -8611,7 +8999,7 @@ gp_XYZ _LayerEdge::smoothNefPolygon() { ////////////////////////////////// NEW gp_XYZ newPos(0,0,0); - // get a plane to seach a solution on + // get a plane to search a solution on size_t i; gp_XYZ center(0,0,0); @@ -8936,6 +9324,11 @@ void _LayerEdge::Block( _SolidData& data ) //if ( Is( BLOCKED )) return; Set( BLOCKED ); + SMESH_Comment msg( "#BLOCK shape="); + msg << data.GetShapeEdges( this )->_shapeID + << ", nodes " << _nodes[0]->GetID() << ", " << _nodes.back()->GetID(); + dumpCmd( msg + " -- BEGIN") + _maxLen = _len; std::queue<_LayerEdge*> queue; queue.push( this ); @@ -8958,9 +9351,11 @@ void _LayerEdge::Block( _SolidData& data ) minDist = Min( pSrc.SquareDistance( pTgtN ), minDist ); minDist = Min( pTgt.SquareDistance( pSrcN ), minDist ); double newMaxLen = edge->_maxLen + 0.5 * Sqrt( minDist ); - if ( edge->_nodes[0]->getshapeId() == neibor->_nodes[0]->getshapeId() ) + //if ( edge->_nodes[0]->getshapeId() == neibor->_nodes[0]->getshapeId() ) viscous_layers_00/A3 { newMaxLen *= edge->_lenFactor / neibor->_lenFactor; + // newMaxLen *= Min( edge->_lenFactor / neibor->_lenFactor, + // neibor->_lenFactor / edge->_lenFactor ); } if ( neibor->_maxLen > newMaxLen ) { @@ -8978,6 +9373,7 @@ void _LayerEdge::Block( _SolidData& data ) } } } + dumpCmd( msg + " -- END") } //================================================================================ @@ -9112,10 +9508,49 @@ void _LayerEdge::SmoothPos( const vector< double >& segLen, const double tol ) //================================================================================ /*! - * \brief Create layers of prisms + * \brief Print flags */ //================================================================================ +std::string _LayerEdge::DumpFlags() const +{ + SMESH_Comment dump; + for ( int flag = 1; flag < 0x1000000; flag *= 2 ) + if ( _flags & flag ) + { + EFlags f = (EFlags) flag; + switch ( f ) { + case TO_SMOOTH: dump << "TO_SMOOTH"; break; + case MOVED: dump << "MOVED"; break; + case SMOOTHED: dump << "SMOOTHED"; break; + case DIFFICULT: dump << "DIFFICULT"; break; + case ON_CONCAVE_FACE: dump << "ON_CONCAVE_FACE"; break; + case BLOCKED: dump << "BLOCKED"; break; + case INTERSECTED: dump << "INTERSECTED"; break; + case NORMAL_UPDATED: dump << "NORMAL_UPDATED"; break; + case UPD_NORMAL_CONV: dump << "UPD_NORMAL_CONV"; break; + case MARKED: dump << "MARKED"; break; + case MULTI_NORMAL: dump << "MULTI_NORMAL"; break; + case NEAR_BOUNDARY: dump << "NEAR_BOUNDARY"; break; + case SMOOTHED_C1: dump << "SMOOTHED_C1"; break; + case DISTORTED: dump << "DISTORTED"; break; + case RISKY_SWOL: dump << "RISKY_SWOL"; break; + case SHRUNK: dump << "SHRUNK"; break; + case UNUSED_FLAG: dump << "UNUSED_FLAG"; break; + } + dump << " "; + } + cout << dump << endl; + return dump; +} + +//================================================================================ +/*! + case brief: + default: +*/ +//================================================================================ + bool _ViscousBuilder::refine(_SolidData& data) { SMESH_MesherHelper& helper = data.GetHelper(); @@ -9129,7 +9564,7 @@ bool _ViscousBuilder::refine(_SolidData& data) double f,l, u = 0; gp_XY uv; vector< gp_XYZ > pos3D; - bool isOnEdge; + bool isOnEdge, isTooConvexFace = false; TGeomID prevBaseId = -1; TNode2Edge* n2eMap = 0; TNode2Edge::iterator n2e; @@ -9173,6 +9608,9 @@ bool _ViscousBuilder::refine(_SolidData& data) for ( size_t j = 0; j < eos._eosC1[i]->_edges.size(); ++j ) eos._eosC1[i]->_edges[j]->Set( _LayerEdge::SMOOTHED_C1 ); } + isTooConvexFace = false; + if ( _ConvexFace* cf = data.GetConvexFace( eos._shapeID )) + isTooConvexFace = cf->_isTooCurved; } vector< double > segLen; @@ -9188,8 +9626,8 @@ bool _ViscousBuilder::refine(_SolidData& data) if ( eos._sWOL.IsNull() ) { bool useNormal = true; - bool usePos = false; - bool smoothed = false; + bool usePos = false; + bool smoothed = false; double preci = 0.1 * edge._len; if ( eos._toSmooth && edge._pos.size() > 2 ) { @@ -9197,8 +9635,7 @@ bool _ViscousBuilder::refine(_SolidData& data) } if ( smoothed ) { - if ( !surface.IsNull() && - !data._convexFaces.count( eos._shapeID )) // edge smoothed on FACE + if ( !surface.IsNull() && !isTooConvexFace ) // edge smoothed on FACE { useNormal = usePos = false; gp_Pnt2d uv = helper.GetNodeUV( geomFace, edge._nodes[0] ); @@ -9462,7 +9899,6 @@ bool _ViscousBuilder::refine(_SolidData& data) set< vector* > nnSet; set< int > degenEdgeInd; vector degenVols; - vector isRiskySWOL; TopExp_Explorer exp( data._solid, TopAbs_FACE ); for ( ; exp.More(); exp.Next() ) @@ -9480,7 +9916,6 @@ bool _ViscousBuilder::refine(_SolidData& data) nnVec.resize( nbNodes ); nnSet.clear(); degenEdgeInd.clear(); - isRiskySWOL.resize( nbNodes ); size_t maxZ = 0, minZ = std::numeric_limits::max(); SMDS_NodeIteratorPtr nIt = face->nodeIterator(); for ( int iN = 0; iN < nbNodes; ++iN ) @@ -9491,7 +9926,6 @@ bool _ViscousBuilder::refine(_SolidData& data) nnVec[ i ] = & edge->_nodes; maxZ = std::max( maxZ, nnVec[ i ]->size() ); minZ = std::min( minZ, nnVec[ i ]->size() ); - //isRiskySWOL[ i ] = edge->Is( _LayerEdge::RISKY_SWOL ); if ( helper.HasDegeneratedEdges() ) nnSet.insert( nnVec[ i ]); @@ -9600,7 +10034,7 @@ bool _ViscousBuilder::refine(_SolidData& data) if ( !err || err->IsOK() ) { err.reset( new SMESH_ComputeError( COMPERR_WARNING, - "Degenerated volumes created" )); + "Bad quality volumes created" )); err->myBadElements.insert( err->myBadElements.end(), degenVols.begin(),degenVols.end() ); } @@ -9615,71 +10049,94 @@ bool _ViscousBuilder::refine(_SolidData& data) */ //================================================================================ -bool _ViscousBuilder::shrink() +bool _ViscousBuilder::shrink(_SolidData& theData) { - // make map of (ids of FACEs to shrink mesh on) to (_SolidData containing _LayerEdge's - // inflated along FACE or EDGE) - map< TGeomID, _SolidData* > f2sdMap; + // make map of (ids of FACEs to shrink mesh on) to (list of _SolidData containing + // _LayerEdge's inflated along FACE or EDGE) + map< TGeomID, list< _SolidData* > > f2sdMap; for ( size_t i = 0 ; i < _sdVec.size(); ++i ) { _SolidData& data = _sdVec[i]; - TopTools_MapOfShape FFMap; map< TGeomID, TopoDS_Shape >::iterator s2s = data._shrinkShape2Shape.begin(); for (; s2s != data._shrinkShape2Shape.end(); ++s2s ) - if ( s2s->second.ShapeType() == TopAbs_FACE ) + if ( s2s->second.ShapeType() == TopAbs_FACE && !_shrinkedFaces.Contains( s2s->second )) { - f2sdMap.insert( make_pair( getMeshDS()->ShapeToIndex( s2s->second ), &data )); + f2sdMap[ getMeshDS()->ShapeToIndex( s2s->second )].push_back( &data ); - if ( FFMap.Add( (*s2s).second )) - // Put mesh faces on the shrinked FACE to the proxy sub-mesh to avoid - // usage of mesh faces made in addBoundaryElements() by the 3D algo or - // by StdMeshers_QuadToTriaAdaptor - if ( SMESHDS_SubMesh* smDS = getMeshDS()->MeshElements( s2s->second )) + // Put mesh faces on the shrinked FACE to the proxy sub-mesh to avoid + // usage of mesh faces made in addBoundaryElements() by the 3D algo or + // by StdMeshers_QuadToTriaAdaptor + if ( SMESHDS_SubMesh* smDS = getMeshDS()->MeshElements( s2s->second )) + { + SMESH_ProxyMesh::SubMesh* proxySub = + data._proxyMesh->getFaceSubM( TopoDS::Face( s2s->second ), /*create=*/true); + if ( proxySub->NbElements() == 0 ) { - SMESH_ProxyMesh::SubMesh* proxySub = - data._proxyMesh->getFaceSubM( TopoDS::Face( s2s->second ), /*create=*/true); SMDS_ElemIteratorPtr fIt = smDS->GetElements(); while ( fIt->more() ) - proxySub->AddElement( fIt->next() ); - // as a result 3D algo will use elements from proxySub and not from smDS + { + const SMDS_MeshElement* f = fIt->next(); + // as a result 3D algo will use elements from proxySub and not from smDS + proxySub->AddElement( f ); + f->setIsMarked( true ); + + // Mark nodes on the FACE to discriminate them from nodes + // added by addBoundaryElements(); marked nodes are to be smoothed while shrink() + for ( int iN = 0, nbN = f->NbNodes(); iN < nbN; ++iN ) + { + const SMDS_MeshNode* n = f->GetNode( iN ); + if ( n->GetPosition()->GetDim() == 2 ) + n->setIsMarked( true ); + } + } } + } } } SMESH_MesherHelper helper( *_mesh ); helper.ToFixNodeParameters( true ); - // EDGE's to shrink + // EDGEs to shrink map< TGeomID, _Shrinker1D > e2shrMap; vector< _EdgesOnShape* > subEOS; vector< _LayerEdge* > lEdges; - // loop on FACES to srink mesh on - map< TGeomID, _SolidData* >::iterator f2sd = f2sdMap.begin(); + // loop on FACEs to srink mesh on + map< TGeomID, list< _SolidData* > >::iterator f2sd = f2sdMap.begin(); for ( ; f2sd != f2sdMap.end(); ++f2sd ) { - _SolidData& data = *f2sd->second; + list< _SolidData* > & dataList = f2sd->second; + if ( dataList.front()->_n2eMap.empty() || + dataList.back() ->_n2eMap.empty() ) + continue; // not yet computed + if ( dataList.front() != &theData && + dataList.back() != &theData ) + continue; + + _SolidData& data = *dataList.front(); + _SolidData* data2 = dataList.size() > 1 ? dataList.back() : 0; const TopoDS_Face& F = TopoDS::Face( getMeshDS()->IndexToShape( f2sd->first )); SMESH_subMesh* sm = _mesh->GetSubMesh( F ); SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); - Handle(Geom_Surface) surface = BRep_Tool::Surface(F); + Handle(Geom_Surface) surface = BRep_Tool::Surface( F ); - helper.SetSubShape(F); + _shrinkedFaces.Add( F ); + helper.SetSubShape( F ); // =========================== // Prepare data for shrinking // =========================== - // Collect nodes to smooth, as src nodes are not yet replaced by tgt ones - // and hence all nodes on a FACE connected to 2d elements are to be smoothed + // Collect nodes to smooth (they are marked at the beginning of this method) vector < const SMDS_MeshNode* > smoothNodes; { SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); while ( nIt->more() ) { const SMDS_MeshNode* n = nIt->next(); - if ( n->NbInverseElements( SMDSAbs_Face ) > 0 ) + if ( n->isMarked() ) smoothNodes.push_back( n ); } } @@ -9691,10 +10148,10 @@ bool _ViscousBuilder::shrink() { vector<_Simplex> simplices; _Simplex::GetSimplices( smoothNodes[0], simplices, ignoreShapes ); - helper.GetNodeUV( F, simplices[0]._nPrev, 0, &isOkUV ); // fix UV of silpmex nodes + helper.GetNodeUV( F, simplices[0]._nPrev, 0, &isOkUV ); // fix UV of simplex nodes helper.GetNodeUV( F, simplices[0]._nNext, 0, &isOkUV ); gp_XY uv = helper.GetNodeUV( F, smoothNodes[0], 0, &isOkUV ); - if ( !simplices[0].IsForward(uv, smoothNodes[0], F, helper,refSign) ) + if ( !simplices[0].IsForward(uv, smoothNodes[0], F, helper, refSign )) refSign = -1; } @@ -9710,8 +10167,13 @@ bool _ViscousBuilder::shrink() if ( data._noShrinkShapes.count( subID )) continue; _EdgesOnShape* eos = data.GetShapeEdges( subID ); - if ( !eos || eos->_sWOL.IsNull() ) continue; - + if ( !eos || eos->_sWOL.IsNull() ) + if ( data2 ) // check in adjacent SOLID + { + eos = data2->GetShapeEdges( subID ); + if ( !eos || eos->_sWOL.IsNull() ) + continue; + } subEOS.push_back( eos ); for ( size_t i = 0; i < eos->_edges.size(); ++i ) @@ -9744,7 +10206,7 @@ bool _ViscousBuilder::shrink() while ( fIt->more() ) { const SMDS_MeshElement* f = fIt->next(); - if ( !smDS->Contains( f )) + if ( !smDS->Contains( f ) || !f->isMarked() ) continue; SMDS_NodeIteratorPtr nIt = f->nodeIterator(); for ( int iN = 0; nIt->more(); ++iN ) @@ -9771,7 +10233,7 @@ bool _ViscousBuilder::shrink() { const SMDS_MeshNode* n = smoothNodes[i]; nodesToSmooth[ i ]._node = n; - // src nodes must be replaced by tgt nodes to have tgt nodes in _simplices + // src nodes must be already replaced by tgt nodes to have tgt nodes in _simplices _Simplex::GetSimplices( n, nodesToSmooth[ i ]._simplices, ignoreShapes, 0, sortSimplices); // fix up incorrect uv of nodes on the FACE helper.GetNodeUV( F, n, 0, &isOkUV); @@ -9802,6 +10264,10 @@ bool _ViscousBuilder::shrink() { _LayerEdge& edge = * eos._edges[i]; _Simplex::GetSimplices( /*tgtNode=*/edge._nodes.back(), edge._simplices, ignoreShapes ); + + // additionally mark tgt node; only marked nodes will be used in SetNewLength2d() + // not-marked nodes are those added by refine() + edge._nodes.back()->setIsMarked( true ); } } } @@ -9938,6 +10404,8 @@ bool _ViscousBuilder::shrink() if ( !errMsg.empty() ) // Try to re-compute the shrink FACE { + debugMsg( "Re-compute FACE " << f2sd->first << " because " << errMsg ); + // remove faces SMESHDS_SubMesh* psm = data._proxyMesh->getFaceSubM( F ); { @@ -9977,7 +10445,8 @@ bool _ViscousBuilder::shrink() { _LayerEdge* edge = subEOS[iS]->_edges[i]; SMDS_MeshNode* tgtNode = const_cast< SMDS_MeshNode*& >( edge->_nodes.back() ); - if ( edge->_pos.empty() ) continue; + if ( edge->_pos.empty() || + edge->Is( _LayerEdge::SHRUNK )) continue; if ( subEOS[iS]->SWOLType() == TopAbs_FACE ) { SMDS_FacePosition* pos = static_cast( tgtNode->GetPosition() ); @@ -10133,6 +10602,8 @@ bool _ViscousBuilder::shrink() // Set an event listener to clear FACE sub-mesh together with SOLID sub-mesh VISCOUS_3D::ToClearSubWithMain( sm, data._solid ); + if ( data2 ) + VISCOUS_3D::ToClearSubWithMain( sm, data2->_solid ); } // loop on FACES to srink mesh on @@ -10165,6 +10636,7 @@ bool _ViscousBuilder::prepareEdgeToShrink( _LayerEdge& edge, if ( tgtNode->GetPosition()->GetDim() != 2 ) // not inflated edge { edge._pos.clear(); + edge.Set( _LayerEdge::SHRUNK ); return srcNode == tgtNode; } gp_XY srcUV ( edge._pos[0].X(), edge._pos[0].Y() ); //helper.GetNodeUV( F, srcNode ); @@ -10175,7 +10647,7 @@ bool _ViscousBuilder::prepareEdgeToShrink( _LayerEdge& edge, edge._normal.SetCoord( uvDir.X(),uvDir.Y(), 0 ); edge._len = uvLen; - edge._pos.resize(1); + //edge._pos.resize(1); edge._pos[0].SetCoord( tgtUV.X(), tgtUV.Y(), 0 ); // set UV of source node to target node @@ -10188,6 +10660,7 @@ bool _ViscousBuilder::prepareEdgeToShrink( _LayerEdge& edge, if ( tgtNode->GetPosition()->GetDim() != 1 ) // not inflated edge { edge._pos.clear(); + edge.Set( _LayerEdge::SHRUNK ); return srcNode == tgtNode; } const TopoDS_Edge& E = TopoDS::Edge( eos._sWOL ); @@ -10209,16 +10682,17 @@ bool _ViscousBuilder::prepareEdgeToShrink( _LayerEdge& edge, double uSrc = helper.GetNodeU( E, srcNode, n2 ); double uTgt = helper.GetNodeU( E, tgtNode, srcNode ); - double u2 = helper.GetNodeU( E, n2, srcNode ); + double u2 = helper.GetNodeU( E, n2, srcNode ); - edge._pos.clear(); + //edge._pos.clear(); if ( fabs( uSrc-uTgt ) < 0.99 * fabs( uSrc-u2 )) { // tgtNode is located so that it does not make faces with wrong orientation + edge.Set( _LayerEdge::SHRUNK ); return true; } - edge._pos.resize(1); + //edge._pos.resize(1); edge._pos[0].SetCoord( U_TGT, uTgt ); edge._pos[0].SetCoord( U_SRC, uSrc ); edge._pos[0].SetCoord( LEN_TGT, fabs( uSrc-uTgt )); @@ -10439,7 +10913,7 @@ bool _LayerEdge::SetNewLength2d( Handle(Geom_Surface)& surface, _EdgesOnShape& eos, SMESH_MesherHelper& helper ) { - if ( _pos.empty() ) + if ( Is( SHRUNK )) return false; // already at the target position SMDS_MeshNode* tgtNode = const_cast< SMDS_MeshNode*& >( _nodes.back() ); @@ -10456,6 +10930,10 @@ bool _LayerEdge::SetNewLength2d( Handle(Geom_Surface)& surface, double stepSize = 1e100; for ( size_t i = 0; i < _simplices.size(); ++i ) { + if ( !_simplices[i]._nPrev->isMarked() || + !_simplices[i]._nNext->isMarked() ) + continue; // simplex of quadrangle created by addBoundaryElements() + // find intersection of 2 lines: curUV-tgtUV and that connecting simplex nodes gp_XY uvN1 = helper.GetNodeUV( F, _simplices[i]._nPrev ); gp_XY uvN2 = helper.GetNodeUV( F, _simplices[i]._nNext ); @@ -10471,7 +10949,8 @@ bool _LayerEdge::SetNewLength2d( Handle(Geom_Surface)& surface, if ( uvLen <= stepSize ) { newUV = tgtUV; - _pos.clear(); + Set( SHRUNK ); + //_pos.clear(); } else if ( stepSize > 0 ) { @@ -10504,7 +10983,8 @@ bool _LayerEdge::SetNewLength2d( Handle(Geom_Surface)& surface, double newU = _pos[0].Coord( U_TGT ); if ( lenTgt < 0.99 * fabs( uSrc-u2 )) // n2 got out of src-tgt range { - _pos.clear(); + Set( _LayerEdge::SHRUNK ); + //_pos.clear(); } else { @@ -10737,7 +11217,7 @@ void _Shrinker1D::AddEdge( const _LayerEdge* e, _done = false; } // check _LayerEdge - if ( e == _edges[0] || e == _edges[1] ) + if ( e == _edges[0] || e == _edges[1] || e->_nodes.size() < 2 ) return; if ( eos.SWOLType() != TopAbs_EDGE ) throw SALOME_Exception(LOCALIZED("Wrong _LayerEdge is added")); @@ -10774,9 +11254,18 @@ void _Shrinker1D::AddEdge( const _LayerEdge* e, while ( nIt->more() ) { const SMDS_MeshNode* node = nIt->next(); + + // skip refinement nodes if ( node->NbInverseElements(SMDSAbs_Edge) == 0 || node == tgtNode0 || node == tgtNode1 ) - continue; // refinement nodes + continue; + bool hasMarkedFace = false; + SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() && !hasMarkedFace ) + hasMarkedFace = fIt->next()->isMarked(); + if ( !hasMarkedFace ) + continue; + _nodes.push_back( node ); _initU.push_back( helper.GetNodeU( _geomEdge, node )); double len = GCPnts_AbscissaPoint::Length(aCurve, f, _initU.back()); @@ -10809,8 +11298,8 @@ void _Shrinker1D::Compute(bool set3D, SMESH_MesherHelper& helper) if ( !e ) e = _edges[1]; if ( !e ) return; - _done = (( !_edges[0] || _edges[0]->_pos.empty() ) && - ( !_edges[1] || _edges[1]->_pos.empty() )); + _done = (( !_edges[0] || _edges[0]->Is( _LayerEdge::SHRUNK )) && + ( !_edges[1] || _edges[1]->Is( _LayerEdge::SHRUNK ))); double f,l; if ( set3D || _done ) @@ -10891,11 +11380,12 @@ void _Shrinker1D::SwapSrcTgtNodes( SMESHDS_Mesh* mesh ) if ( !eSubMesh ) return; const SMDS_MeshNode* srcNode = _edges[i]->_nodes[0]; const SMDS_MeshNode* tgtNode = _edges[i]->_nodes.back(); + const SMDS_MeshNode* scdNode = _edges[i]->_nodes[1]; SMDS_ElemIteratorPtr eIt = srcNode->GetInverseElementIterator(SMDSAbs_Edge); while ( eIt->more() ) { const SMDS_MeshElement* e = eIt->next(); - if ( !eSubMesh->Contains( e )) + if ( !eSubMesh->Contains( e ) || e->GetNodeIndex( scdNode ) >= 0 ) continue; SMDS_ElemIteratorPtr nIt = e->nodesIterator(); for ( int iN = 0; iN < e->NbNodes(); ++iN ) @@ -10914,21 +11404,22 @@ void _Shrinker1D::SwapSrcTgtNodes( SMESHDS_Mesh* mesh ) */ //================================================================================ -bool _ViscousBuilder::addBoundaryElements() +bool _ViscousBuilder::addBoundaryElements(_SolidData& data) { SMESH_MesherHelper helper( *_mesh ); vector< const SMDS_MeshNode* > faceNodes; - for ( size_t i = 0; i < _sdVec.size(); ++i ) + //for ( size_t i = 0; i < _sdVec.size(); ++i ) { - _SolidData& data = _sdVec[i]; + //_SolidData& data = _sdVec[i]; TopTools_IndexedMapOfShape geomEdges; TopExp::MapShapes( data._solid, TopAbs_EDGE, geomEdges ); for ( int iE = 1; iE <= geomEdges.Extent(); ++iE ) { const TopoDS_Edge& E = TopoDS::Edge( geomEdges(iE)); - if ( data._noShrinkShapes.count( getMeshDS()->ShapeToIndex( E ))) + const TGeomID edgeID = getMeshDS()->ShapeToIndex( E ); + if ( data._noShrinkShapes.count( edgeID )) continue; // Get _LayerEdge's based on E @@ -10977,10 +11468,9 @@ bool _ViscousBuilder::addBoundaryElements() // Find out orientation and type of face to create bool reverse = false, isOnFace; - - map< TGeomID, TopoDS_Shape >::iterator e2f = - data._shrinkShape2Shape.find( getMeshDS()->ShapeToIndex( E )); TopoDS_Shape F; + + map< TGeomID, TopoDS_Shape >::iterator e2f = data._shrinkShape2Shape.find( edgeID ); if (( isOnFace = ( e2f != data._shrinkShape2Shape.end() ))) { F = e2f->second.Oriented( TopAbs_FORWARD ); @@ -10990,17 +11480,12 @@ bool _ViscousBuilder::addBoundaryElements() if ( helper.IsReversedSubMesh( TopoDS::Face(F) )) reverse = !reverse; } - else + else if ( !data._ignoreFaceIds.count( e2f->first )) { // find FACE with layers sharing E - PShapeIteratorPtr fIt = helper.GetAncestors( E, *_mesh, TopAbs_FACE ); - while ( fIt->more() && F.IsNull() ) - { - const TopoDS_Shape* pF = fIt->next(); - if ( helper.IsSubShape( *pF, data._solid) && - !data._ignoreFaceIds.count( e2f->first )) - F = *pF; - } + PShapeIteratorPtr fIt = helper.GetAncestors( E, *_mesh, TopAbs_FACE, &data._solid ); + if ( fIt->more() ) + F = *( fIt->next() ); } // Find the sub-mesh to add new faces SMESHDS_SubMesh* sm = 0; @@ -11011,18 +11496,44 @@ bool _ViscousBuilder::addBoundaryElements() if ( !sm ) return error("error in addBoundaryElements()", data._index); + // Find a proxy sub-mesh of the FACE of an adjacent SOLID, which will use the new boundary + // faces for 3D meshing (PAL23414) + SMESHDS_SubMesh* adjSM = 0; + if ( isOnFace ) + { + const TGeomID faceID = sm->GetID(); + PShapeIteratorPtr soIt = helper.GetAncestors( F, *_mesh, TopAbs_SOLID ); + while ( const TopoDS_Shape* solid = soIt->next() ) + if ( !solid->IsSame( data._solid )) + { + size_t iData = _solids.FindIndex( *solid ) - 1; + if ( iData < _sdVec.size() && + _sdVec[ iData ]._ignoreFaceIds.count( faceID ) && + _sdVec[ iData ]._shrinkShape2Shape.count( edgeID ) == 0 ) + { + SMESH_ProxyMesh::SubMesh* proxySub = + _sdVec[ iData ]._proxyMesh->getFaceSubM( TopoDS::Face( F ), /*create=*/false); + if ( proxySub && proxySub->NbElements() > 0 ) + adjSM = proxySub; + } + } + } + // Make faces const int dj1 = reverse ? 0 : 1; const int dj2 = reverse ? 1 : 0; + vector< const SMDS_MeshElement*> ff; // new faces row + SMESHDS_Mesh* m = getMeshDS(); for ( size_t j = 1; j < ledges.size(); ++j ) { vector< const SMDS_MeshNode*>& nn1 = ledges[j-dj1]->_nodes; vector< const SMDS_MeshNode*>& nn2 = ledges[j-dj2]->_nodes; + ff.resize( std::max( nn1.size(), nn2.size() ), NULL ); if ( nn1.size() == nn2.size() ) { if ( isOnFace ) for ( size_t z = 1; z < nn1.size(); ++z ) - sm->AddElement( getMeshDS()->AddFace( nn1[z-1], nn2[z-1], nn2[z], nn1[z] )); + sm->AddElement( ff[z-1] = m->AddFace( nn1[z-1], nn2[z-1], nn2[z], nn1[z] )); else for ( size_t z = 1; z < nn1.size(); ++z ) sm->AddElement( new SMDS_FaceOfNodes( nn1[z-1], nn2[z-1], nn2[z], nn1[z] )); @@ -11031,7 +11542,7 @@ bool _ViscousBuilder::addBoundaryElements() { if ( isOnFace ) for ( size_t z = 1; z < nn2.size(); ++z ) - sm->AddElement( getMeshDS()->AddFace( nn1[0], nn2[z-1], nn2[z] )); + sm->AddElement( ff[z-1] = m->AddFace( nn1[0], nn2[z-1], nn2[z] )); else for ( size_t z = 1; z < nn2.size(); ++z ) sm->AddElement( new SMDS_FaceOfNodes( nn1[0], nn2[z-1], nn2[z] )); @@ -11040,11 +11551,19 @@ bool _ViscousBuilder::addBoundaryElements() { if ( isOnFace ) for ( size_t z = 1; z < nn1.size(); ++z ) - sm->AddElement( getMeshDS()->AddFace( nn1[z-1], nn2[0], nn1[z] )); + sm->AddElement( ff[z-1] = m->AddFace( nn1[z-1], nn2[0], nn1[z] )); else for ( size_t z = 1; z < nn1.size(); ++z ) sm->AddElement( new SMDS_FaceOfNodes( nn1[z-1], nn2[0], nn2[z] )); } + + if ( adjSM ) // add faces to a proxy SM of the adjacent SOLID + { + for ( size_t z = 0; z < ff.size(); ++z ) + if ( ff[ z ]) + adjSM->AddElement( ff[ z ]); + ff.clear(); + } } // Make edges @@ -11055,7 +11574,7 @@ bool _ViscousBuilder::addBoundaryElements() if ( eos && eos->SWOLType() == TopAbs_EDGE ) { vector< const SMDS_MeshNode*>& nn = edge->_nodes; - if ( nn.size() < 2 || nn[1]->GetInverseElementIterator( SMDSAbs_Edge )->more() ) + if ( nn.size() < 2 || nn[1]->NbInverseElements( SMDSAbs_Edge ) >= 2 ) continue; helper.SetSubShape( eos->_sWOL ); helper.SetElementsOnShape( true );