+//================================================================================
+/*!
+ * \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,
+ bool 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 && !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 );
+ }
+ }
+
+#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_F") << 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
+}
+