+ // ignore intersection with intFace of an adjacent FACE
+ if ( dist > 0 )
+ {
+ bool toIgnore = false;
+ if ( eos._toSmooth )
+ {
+ const TopoDS_Shape& S = getMeshDS()->IndexToShape( intFace->getshapeId() );
+ if ( !S.IsNull() && S.ShapeType() == TopAbs_FACE )
+ {
+ 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
+ {
+ gp_XYZ normal;
+ if ( SMESH_MeshAlgos::FaceNormal( intFace, normal, /*normalized=*/true ))
+ toIgnore = ( normal * eos._edges[i]->_normal > -0.5 );
+ }
+ }
+ }
+ if ( !toIgnore ) // check if the edge is a neighbor of intFace
+ {
+ for ( size_t iN = 0; !toIgnore && iN < eos._edges[i]->_neibors.size(); ++iN )
+ {
+ int nInd = intFace->GetNodeIndex( eos._edges[i]->_neibors[ iN ]->_nodes.back() );
+ toIgnore = ( nInd >= 0 );
+ }
+ }
+ if ( toIgnore )
+ continue;
+ }
+
+ // intersection not ignored
+
+ if ( toBlockInfaltion &&
+ dist < ( eos._edges[i]->_len * theThickToIntersection ))
+ {
+ eos._edges[i]->Set( _LayerEdge::INTERSECTED ); // not to intersect
+ eos._edges[i]->Block( data ); // not to inflate
+
+ if ( _EdgesOnShape* eof = data.GetShapeEdges( intFace->getshapeId() ))
+ {
+ // block _LayerEdge's, on top of which intFace is
+ if ( const _TmpMeshFace* f = dynamic_cast< const _TmpMeshFace*>( intFace ))
+ {
+ const SMDS_MeshElement* srcFace =
+ eof->_subMesh->GetSubMeshDS()->GetElement( f->getIdInShape() );
+ SMDS_ElemIteratorPtr nIt = srcFace->nodesIterator();
+ while ( nIt->more() )
+ {
+ const SMDS_MeshNode* srcNode = static_cast<const SMDS_MeshNode*>( nIt->next() );
+ TNode2Edge::iterator n2e = data._n2eMap.find( srcNode );
+ if ( n2e != data._n2eMap.end() )
+ n2e->second->Block( data );
+ }
+ }
+ }
+ }
+
+ if ( isShorterDist )
+ {
+ distToIntersection = dist;
+ le = eos._edges[i];
+ closestFace = intFace;
+ }
+
+ } // if ( toBlockInfaltion || isShorterDist )
+ } // loop on eos._edges
+ } // loop on data._edgesOnShape
+
+ if ( closestFace && le )
+ {
+#ifdef __myDEBUG
+ SMDS_MeshElement::iterator nIt = closestFace->begin_nodes();
+ cout << "Shortest distance: _LayerEdge nodes: tgt " << le->_nodes.back()->GetID()
+ << " src " << le->_nodes[0]->GetID()<< ", intersection with face ("
+ << (*nIt++)->GetID()<<" "<< (*nIt++)->GetID()<<" "<< (*nIt++)->GetID()
+ << ") distance = " << distToIntersection<< endl;
+#endif
+ }
+
+ return true;
+}
+
+//================================================================================
+/*!
+ * \brief try to fix bad simplices by removing the last inflation step of some _LayerEdge's
+ * \param [in,out] badSmooEdges - _LayerEdge's to fix
+ * \return int - resulting nb of bad _LayerEdge's
+ */
+//================================================================================
+
+int _ViscousBuilder::invalidateBadSmooth( _SolidData& data,
+ SMESH_MesherHelper& helper,
+ vector< _LayerEdge* >& badSmooEdges,
+ vector< _EdgesOnShape* >& eosC1,
+ const int infStep )
+{
+ if ( badSmooEdges.empty() || infStep == 0 ) return 0;
+
+ dumpFunction(SMESH_Comment("invalidateBadSmooth")<<"_S"<<eosC1[0]->_shapeID<<"_InfStep"<<infStep);
+
+ enum {
+ INVALIDATED = _LayerEdge::UNUSED_FLAG,
+ TO_INVALIDATE = _LayerEdge::UNUSED_FLAG * 2,
+ ADDED = _LayerEdge::UNUSED_FLAG * 4
+ };
+ data.UnmarkEdges( TO_INVALIDATE & INVALIDATED & ADDED );
+
+ double vol;
+ bool haveInvalidated = true;
+ while ( haveInvalidated )
+ {
+ haveInvalidated = false;
+ for ( size_t i = 0; i < badSmooEdges.size(); ++i )
+ {
+ _LayerEdge* edge = badSmooEdges[i];
+ _EdgesOnShape* eos = data.GetShapeEdges( edge );
+ edge->Set( ADDED );
+ bool invalidated = false;
+ if ( edge->Is( TO_INVALIDATE ) && edge->NbSteps() > 1 )
+ {
+ edge->InvalidateStep( edge->NbSteps(), *eos, /*restoreLength=*/true );
+ edge->Block( data );
+ edge->Set( INVALIDATED );
+ edge->Unset( TO_INVALIDATE );
+ invalidated = true;
+ haveInvalidated = true;
+ }
+
+ // look for _LayerEdge's of bad _simplices
+ int nbBad = 0;
+ SMESH_TNodeXYZ tgtXYZ = edge->_nodes.back();
+ gp_XYZ prevXYZ1 = edge->PrevCheckPos( eos );
+ //const gp_XYZ& prevXYZ2 = edge->PrevPos();
+ for ( size_t j = 0; j < edge->_simplices.size(); ++j )
+ {
+ if (( edge->_simplices[j].IsForward( &prevXYZ1, &tgtXYZ, vol ))/* &&
+ ( &prevXYZ1 == &prevXYZ2 || edge->_simplices[j].IsForward( &prevXYZ2, &tgtXYZ, vol ))*/)
+ continue;
+
+ bool isBad = true;
+ _LayerEdge* ee[2] = { 0,0 };
+ for ( size_t iN = 0; iN < edge->_neibors.size() && !ee[1] ; ++iN )
+ if ( edge->_simplices[j].Includes( edge->_neibors[iN]->_nodes.back() ))
+ ee[ ee[0] != 0 ] = edge->_neibors[iN];
+
+ int maxNbSteps = Max( ee[0]->NbSteps(), ee[1]->NbSteps() );
+ while ( maxNbSteps > edge->NbSteps() && isBad )
+ {
+ --maxNbSteps;
+ for ( int iE = 0; iE < 2; ++iE )
+ {
+ if ( ee[ iE ]->NbSteps() > maxNbSteps &&
+ ee[ iE ]->NbSteps() > 1 )
+ {
+ _EdgesOnShape* eos = data.GetShapeEdges( ee[ iE ] );
+ ee[ iE ]->InvalidateStep( ee[ iE ]->NbSteps(), *eos, /*restoreLength=*/true );
+ ee[ iE ]->Block( data );
+ ee[ iE ]->Set( INVALIDATED );
+ haveInvalidated = true;
+ }
+ }
+ if (( edge->_simplices[j].IsForward( &prevXYZ1, &tgtXYZ, vol )) /*&&
+ ( &prevXYZ1 == &prevXYZ2 || edge->_simplices[j].IsForward( &prevXYZ2, &tgtXYZ, vol ))*/)
+ isBad = false;
+ }
+ nbBad += isBad;
+ if ( !ee[0]->Is( ADDED )) badSmooEdges.push_back( ee[0] );
+ if ( !ee[1]->Is( ADDED )) badSmooEdges.push_back( ee[1] );
+ ee[0]->Set( ADDED );
+ ee[1]->Set( ADDED );
+ if ( isBad )
+ {
+ ee[0]->Set( TO_INVALIDATE );
+ ee[1]->Set( TO_INVALIDATE );
+ }
+ }
+
+ if ( !invalidated && nbBad > 0 && edge->NbSteps() > 1 )
+ {
+ _EdgesOnShape* eos = data.GetShapeEdges( edge );
+ edge->InvalidateStep( edge->NbSteps(), *eos, /*restoreLength=*/true );
+ edge->Block( data );
+ edge->Set( INVALIDATED );
+ edge->Unset( TO_INVALIDATE );
+ haveInvalidated = true;
+ }
+ } // loop on badSmooEdges
+ } // while ( haveInvalidated )
+
+ // re-smooth on analytical EDGEs
+ for ( size_t i = 0; i < badSmooEdges.size(); ++i )
+ {
+ _LayerEdge* edge = badSmooEdges[i];
+ if ( !edge->Is( INVALIDATED )) continue;
+
+ _EdgesOnShape* eos = data.GetShapeEdges( edge );
+ if ( eos->ShapeType() == TopAbs_VERTEX )
+ {
+ PShapeIteratorPtr eIt = helper.GetAncestors( eos->_shape, *_mesh, TopAbs_EDGE );
+ while ( const TopoDS_Shape* e = eIt->next() )
+ if ( _EdgesOnShape* eoe = data.GetShapeEdges( *e ))
+ if ( eoe->_edgeSmoother && eoe->_edgeSmoother->isAnalytic() )
+ {
+ // TopoDS_Face F; Handle(ShapeAnalysis_Surface) surface;
+ // if ( eoe->SWOLType() == TopAbs_FACE ) {
+ // F = TopoDS::Face( eoe->_sWOL );
+ // surface = helper.GetSurface( F );
+ // }
+ // eoe->_edgeSmoother->Perform( data, surface, F, helper );
+ eoe->_edgeSmoother->_anaCurve.Nullify();
+ }
+ }
+ }
+
+
+ // check result of invalidation
+
+ int nbBad = 0;
+ for ( size_t iEOS = 0; iEOS < eosC1.size(); ++iEOS )
+ {
+ for ( size_t i = 0; i < eosC1[ iEOS ]->_edges.size(); ++i )
+ {
+ if ( !eosC1[ iEOS ]->_sWOL.IsNull() ) continue;
+ _LayerEdge* edge = eosC1[ iEOS ]->_edges[i];
+ SMESH_TNodeXYZ tgtXYZ = edge->_nodes.back();
+ gp_XYZ prevXYZ = edge->PrevCheckPos( eosC1[ iEOS ]);
+ for ( size_t j = 0; j < edge->_simplices.size(); ++j )
+ if ( !edge->_simplices[j].IsForward( &prevXYZ, &tgtXYZ, vol ))
+ {
+ ++nbBad;
+ debugMsg("Bad simplex remains ( " << edge->_nodes[0]->GetID()
+ << " "<< tgtXYZ._node->GetID()
+ << " "<< edge->_simplices[j]._nPrev->GetID()
+ << " "<< edge->_simplices[j]._nNext->GetID() << " )" );
+ }
+ }
+ }
+ dumpFunctionEnd();
+
+ return nbBad;
+}
+
+//================================================================================
+/*!
+ * \brief Create an offset surface
+ */
+//================================================================================
+
+void _ViscousBuilder::makeOffsetSurface( _EdgesOnShape& eos, SMESH_MesherHelper& helper )
+{
+ if ( eos._offsetSurf.IsNull() ||
+ eos._edgeForOffset == 0 ||
+ eos._edgeForOffset->Is( _LayerEdge::BLOCKED ))
+ return;
+
+ Handle(ShapeAnalysis_Surface) baseSurface = helper.GetSurface( TopoDS::Face( eos._shape ));
+
+ // find offset
+ gp_Pnt tgtP = SMESH_TNodeXYZ( eos._edgeForOffset->_nodes.back() );
+ /*gp_Pnt2d uv=*/baseSurface->ValueOfUV( tgtP, Precision::Confusion() );
+ double offset = baseSurface->Gap();
+
+ eos._offsetSurf.Nullify();
+
+ try
+ {
+ BRepOffsetAPI_MakeOffsetShape offsetMaker( eos._shape, -offset, Precision::Confusion() );
+ if ( !offsetMaker.IsDone() ) return;
+
+ TopExp_Explorer fExp( offsetMaker.Shape(), TopAbs_FACE );
+ if ( !fExp.More() ) return;
+
+ TopoDS_Face F = TopoDS::Face( fExp.Current() );
+ Handle(Geom_Surface) surf = BRep_Tool::Surface( F );
+ if ( surf.IsNull() ) return;
+
+ eos._offsetSurf = new ShapeAnalysis_Surface( surf );
+ }
+ catch ( Standard_Failure )
+ {
+ }
+}
+
+//================================================================================
+/*!
+ * \brief Put nodes of a curved FACE to its offset surface
+ */
+//================================================================================
+
+void _ViscousBuilder::putOnOffsetSurface( _EdgesOnShape& eos,
+ int infStep,
+ vector< _EdgesOnShape* >& eosC1,
+ int smooStep,
+ int moveAll )
+{
+ _EdgesOnShape * eof = & eos;
+ if ( eos.ShapeType() != TopAbs_FACE ) // eos is a boundary of C1 FACE, look for the FACE eos
+ {
+ eof = 0;
+ for ( size_t i = 0; i < eosC1.size() && !eof; ++i )
+ {
+ if ( eosC1[i]->_offsetSurf.IsNull() ||
+ eosC1[i]->ShapeType() != TopAbs_FACE ||
+ eosC1[i]->_edgeForOffset == 0 ||
+ eosC1[i]->_edgeForOffset->Is( _LayerEdge::BLOCKED ))
+ continue;
+ if ( SMESH_MesherHelper::IsSubShape( eos._shape, eosC1[i]->_shape ))
+ eof = eosC1[i];
+ }
+ }
+ if ( !eof ||
+ eof->_offsetSurf.IsNull() ||
+ eof->ShapeType() != TopAbs_FACE ||
+ eof->_edgeForOffset == 0 ||
+ eof->_edgeForOffset->Is( _LayerEdge::BLOCKED ))
+ return;
+
+ double preci = BRep_Tool::Tolerance( TopoDS::Face( eof->_shape )), vol;
+ for ( size_t i = 0; i < eos._edges.size(); ++i )
+ {
+ _LayerEdge* edge = eos._edges[i];
+ edge->Unset( _LayerEdge::MARKED );
+ if ( edge->Is( _LayerEdge::BLOCKED ) || !edge->_curvature )
+ continue;
+ 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 )
+ nbBlockedAround += edge->_neibors[iN]->Is( _LayerEdge::BLOCKED );
+ if ( nbBlockedAround > 1 )
+ continue;
+
+ 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
+ edge->_curvature->_uv = uv;
+ if ( eof->_offsetSurf->Gap() < 10 * preci ) continue; // same pos
+
+ gp_XYZ newP = eof->_offsetSurf->Value( uv ).XYZ();
+ gp_XYZ prevP = edge->PrevCheckPos();
+ bool ok = true;
+ if ( !moveAll )
+ for ( size_t iS = 0; iS < edge->_simplices.size() && ok; ++iS )
+ {
+ ok = edge->_simplices[iS].IsForward( &prevP, &newP, vol );
+ }
+ if ( ok )
+ {
+ SMDS_MeshNode* n = const_cast< SMDS_MeshNode* >( edge->_nodes.back() );
+ n->setXYZ( newP.X(), newP.Y(), newP.Z());
+ 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;
+ for ( ; i < eos._edges.size(); ++i )
+ if ( eos._edges[i]->Is( _LayerEdge::MARKED ))
+ break;
+ if ( i < eos._edges.size() )
+ {
+ dumpFunction(SMESH_Comment("putOnOffsetSurface_S") << eos._shapeID
+ << "_InfStep" << infStep << "_" << smooStep );
+ for ( ; i < eos._edges.size(); ++i )
+ {
+ if ( eos._edges[i]->Is( _LayerEdge::MARKED ))
+ dumpMove( eos._edges[i]->_nodes.back() );
+ }
+ 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;
+ }
+}
+
+//================================================================================