+ id2eos = convFace._subIdToEOS.begin();
+ for ( ; id2eos != convFace._subIdToEOS.end(); ++id2eos )
+ {
+ _EdgesOnShape& eos = * ( id2eos->second );
+ for ( size_t i = 0; i < eos._edges.size(); ++i )
+ {
+ _LayerEdge* & ledge = eos._edges[ i ];
+ double len = ledge->_len;
+ ledge->InvalidateStep( stepNb + 1, eos, /*restoreLength=*/true );
+ ledge->SetCosin( ledge->_cosin );
+ ledge->SetNewLength( len, eos, helper );
+ }
+ if ( eos.ShapeType() != TopAbs_FACE )
+ for ( size_t i = 0; i < eos._edges.size(); ++i )
+ {
+ _LayerEdge* ledge = eos._edges[ i ];
+ for ( size_t iN = 0; iN < ledge->_neibors.size(); ++iN )
+ {
+ _LayerEdge* neibor = ledge->_neibors[iN];
+ if ( neibor->_nodes[0]->GetPosition()->GetDim() == 2 )
+ {
+ neibor->Set( _LayerEdge::NEAR_BOUNDARY );
+ neibor->Set( _LayerEdge::MOVED );
+ neibor->SetSmooLen( neibor->_len );
+ }
+ }
+ }
+ } // loop on sub-shapes of convFace._face
+
+ // Find FACEs adjacent to convFace._face that got necessity to smooth
+ // as a result of normals modification
+
+ set< _EdgesOnShape* > adjFacesToSmooth;
+ for ( size_t iE = 0; iE < centerCurves.size(); ++iE )
+ {
+ if ( centerCurves[ iE ]._adjFace.IsNull() ||
+ centerCurves[ iE ]._adjFaceToSmooth )
+ continue;
+ for ( size_t iLE = 0; iLE < centerCurves[ iE ]._ledges.size(); ++iLE )
+ {
+ if ( centerCurves[ iE ]._ledges[ iLE ]->_cosin > theMinSmoothCosin )
+ {
+ adjFacesToSmooth.insert( data.GetShapeEdges( centerCurves[ iE ]._adjFace ));
+ break;
+ }
+ }
+ }
+ data.AddShapesToSmooth( adjFacesToSmooth );
+
+ dumpFunctionEnd();
+
+
+ } // loop on data._convexFaces
+
+ return true;
+}
+
+//================================================================================
+/*!
+ * \brief Finds a center of curvature of a surface at a _LayerEdge
+ */
+//================================================================================
+
+bool _ConvexFace::GetCenterOfCurvature( _LayerEdge* ledge,
+ BRepLProp_SLProps& surfProp,
+ SMESH_MesherHelper& helper,
+ gp_Pnt & center ) const
+{
+ gp_XY uv = helper.GetNodeUV( _face, ledge->_nodes[0] );
+ surfProp.SetParameters( uv.X(), uv.Y() );
+ if ( !surfProp.IsCurvatureDefined() )
+ return false;
+
+ const double oriFactor = ( _face.Orientation() == TopAbs_REVERSED ? +1. : -1. );
+ double surfCurvatureMax = surfProp.MaxCurvature() * oriFactor;
+ double surfCurvatureMin = surfProp.MinCurvature() * oriFactor;
+ if ( surfCurvatureMin > surfCurvatureMax )
+ center = surfProp.Value().Translated( surfProp.Normal().XYZ() / surfCurvatureMin * oriFactor );
+ else
+ center = surfProp.Value().Translated( surfProp.Normal().XYZ() / surfCurvatureMax * oriFactor );
+
+ return true;
+}
+
+//================================================================================
+/*!
+ * \brief Check that prisms are not distorted
+ */
+//================================================================================
+
+bool _ConvexFace::CheckPrisms() const
+{
+ double vol = 0;
+ for ( size_t i = 0; i < _simplexTestEdges.size(); ++i )
+ {
+ const _LayerEdge* edge = _simplexTestEdges[i];
+ SMESH_TNodeXYZ tgtXYZ( edge->_nodes.back() );
+ for ( size_t j = 0; j < edge->_simplices.size(); ++j )
+ if ( !edge->_simplices[j].IsForward( edge->_nodes[0], tgtXYZ, vol ))
+ {
+ debugMsg( "Bad simplex of _simplexTestEdges ("
+ << " "<< edge->_nodes[0]->GetID()<< " "<< tgtXYZ._node->GetID()
+ << " "<< edge->_simplices[j]._nPrev->GetID()
+ << " "<< edge->_simplices[j]._nNext->GetID() << " )" );
+ return false;
+ }
+ }
+ return true;
+}
+
+//================================================================================
+/*!
+ * \brief Try to compute a new normal by interpolating normals of _LayerEdge's
+ * stored in this _CentralCurveOnEdge.
+ * \param [in] center - curvature center of a point of another _CentralCurveOnEdge.
+ * \param [in,out] newNormal - current normal at this point, to be redefined
+ * \return bool - true if succeeded.
+ */
+//================================================================================
+
+bool _CentralCurveOnEdge::FindNewNormal( const gp_Pnt& center, gp_XYZ& newNormal )
+{
+ if ( this->_isDegenerated )
+ return false;
+
+ // find two centers the given one lies between
+
+ for ( size_t i = 0, nb = _curvaCenters.size()-1; i < nb; ++i )
+ {
+ double sl2 = 1.001 * _segLength2[ i ];
+
+ double d1 = center.SquareDistance( _curvaCenters[ i ]);
+ if ( d1 > sl2 )
+ continue;
+
+ double d2 = center.SquareDistance( _curvaCenters[ i+1 ]);
+ if ( d2 > sl2 || d2 + d1 < 1e-100 )
+ continue;
+
+ d1 = Sqrt( d1 );
+ d2 = Sqrt( d2 );
+ double r = d1 / ( d1 + d2 );
+ gp_XYZ norm = (( 1. - r ) * _ledges[ i ]->_normal +
+ ( r ) * _ledges[ i+1 ]->_normal );
+ norm.Normalize();
+
+ newNormal += norm;
+ double sz = newNormal.Modulus();
+ if ( sz < 1e-200 )
+ break;
+ newNormal /= sz;
+ return true;
+ }
+ return false;
+}
+
+//================================================================================
+/*!
+ * \brief Set shape members
+ */
+//================================================================================
+
+void _CentralCurveOnEdge::SetShapes( const TopoDS_Edge& edge,
+ const _ConvexFace& convFace,
+ _SolidData& data,
+ SMESH_MesherHelper& helper)
+{
+ _edge = edge;
+
+ PShapeIteratorPtr fIt = helper.GetAncestors( edge, *helper.GetMesh(), TopAbs_FACE );
+ while ( const TopoDS_Shape* F = fIt->next())
+ if ( !convFace._face.IsSame( *F ))
+ {
+ _adjFace = TopoDS::Face( *F );
+ _adjFaceToSmooth = false;
+ // _adjFace already in a smoothing queue ?
+ if ( _EdgesOnShape* eos = data.GetShapeEdges( _adjFace ))
+ _adjFaceToSmooth = eos->_toSmooth;
+ break;
+ }
+}
+
+//================================================================================
+/*!
+ * \brief Looks for intersection of it's last segment with faces
+ * \param distance - returns shortest distance from the last node to intersection
+ */
+//================================================================================
+
+bool _LayerEdge::FindIntersection( SMESH_ElementSearcher& searcher,
+ double & distance,
+ const double& epsilon,
+ _EdgesOnShape& eos,
+ const SMDS_MeshElement** intFace)
+{
+ vector< const SMDS_MeshElement* > suspectFaces;
+ double segLen;
+ gp_Ax1 lastSegment = LastSegment( segLen, eos );
+ searcher.GetElementsNearLine( lastSegment, SMDSAbs_Face, suspectFaces );
+
+ bool segmentIntersected = false;
+ distance = Precision::Infinite();
+ int iFace = -1; // intersected face
+ for ( size_t j = 0 ; j < suspectFaces.size() /*&& !segmentIntersected*/; ++j )
+ {
+ const SMDS_MeshElement* face = suspectFaces[j];
+ if ( face->GetNodeIndex( _nodes.back() ) >= 0 ||
+ face->GetNodeIndex( _nodes[0] ) >= 0 )
+ continue; // face sharing _LayerEdge node
+ const int nbNodes = face->NbCornerNodes();
+ bool intFound = false;
+ double dist;
+ SMDS_MeshElement::iterator nIt = face->begin_nodes();
+ if ( nbNodes == 3 )
+ {
+ intFound = SegTriaInter( lastSegment, *nIt++, *nIt++, *nIt++, dist, epsilon );
+ }
+ else
+ {
+ const SMDS_MeshNode* tria[3];
+ tria[0] = *nIt++;
+ tria[1] = *nIt++;
+ for ( int n2 = 2; n2 < nbNodes && !intFound; ++n2 )
+ {
+ tria[2] = *nIt++;
+ intFound = SegTriaInter(lastSegment, tria[0], tria[1], tria[2], dist, epsilon );
+ tria[1] = tria[2];
+ }
+ }
+ if ( intFound )
+ {
+ if ( dist < segLen*(1.01) && dist > -(_len*_lenFactor-segLen) )
+ segmentIntersected = true;
+ if ( distance > dist )
+ distance = dist, iFace = j;
+ }
+ }
+ if ( intFace ) *intFace = ( iFace != -1 ) ? suspectFaces[iFace] : 0;
+
+ distance -= segLen;
+
+ if ( segmentIntersected )
+ {
+#ifdef __myDEBUG
+ SMDS_MeshElement::iterator nIt = suspectFaces[iFace]->begin_nodes();
+ gp_XYZ intP( lastSegment.Location().XYZ() + lastSegment.Direction().XYZ() * ( distance+segLen ));
+ cout << "nodes: tgt " << _nodes.back()->GetID() << " src " << _nodes[0]->GetID()
+ << ", intersection with face ("
+ << (*nIt++)->GetID()<<" "<< (*nIt++)->GetID()<<" "<< (*nIt++)->GetID()
+ << ") at point (" << intP.X() << ", " << intP.Y() << ", " << intP.Z()
+ << ") distance = " << distance << endl;
+#endif
+ }
+
+ return segmentIntersected;
+}
+
+//================================================================================
+/*!
+ * \brief Returns size and direction of the last segment
+ */
+//================================================================================
+
+gp_Ax1 _LayerEdge::LastSegment(double& segLen, _EdgesOnShape& eos) const
+{
+ // find two non-coincident positions
+ gp_XYZ orig = _pos.back();
+ gp_XYZ vec;
+ int iPrev = _pos.size() - 2;
+ //const double tol = ( _len > 0 ) ? 0.3*_len : 1e-100; // adjusted for IPAL52478 + PAL22576
+ const double tol = ( _len > 0 ) ? ( 1e-6 * _len ) : 1e-100;
+ while ( iPrev >= 0 )
+ {
+ vec = orig - _pos[iPrev];
+ if ( vec.SquareModulus() > tol*tol )
+ break;
+ else
+ iPrev--;
+ }
+
+ // make gp_Ax1
+ gp_Ax1 segDir;
+ if ( iPrev < 0 )
+ {
+ segDir.SetLocation( SMESH_TNodeXYZ( _nodes[0] ));
+ segDir.SetDirection( _normal );
+ segLen = 0;
+ }
+ else
+ {
+ gp_Pnt pPrev = _pos[ iPrev ];
+ if ( !eos._sWOL.IsNull() )
+ {
+ TopLoc_Location loc;
+ if ( eos.SWOLType() == TopAbs_EDGE )
+ {
+ double f,l;
+ Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge( eos._sWOL ), loc, f,l);
+ pPrev = curve->Value( pPrev.X() ).Transformed( loc );
+ }
+ else
+ {
+ Handle(Geom_Surface) surface = BRep_Tool::Surface( TopoDS::Face( eos._sWOL ), loc );
+ pPrev = surface->Value( pPrev.X(), pPrev.Y() ).Transformed( loc );
+ }
+ vec = SMESH_TNodeXYZ( _nodes.back() ) - pPrev.XYZ();
+ }
+ segDir.SetLocation( pPrev );
+ segDir.SetDirection( vec );
+ segLen = vec.Modulus();
+ }
+
+ return segDir;
+}
+
+//================================================================================
+/*!
+ * \brief Return the last position of the target node on a FACE.
+ * \param [in] F - the FACE this _LayerEdge is inflated along
+ * \return gp_XY - result UV
+ */
+//================================================================================
+
+gp_XY _LayerEdge::LastUV( const TopoDS_Face& F, _EdgesOnShape& eos ) const
+{
+ if ( F.IsSame( eos._sWOL )) // F is my FACE
+ return gp_XY( _pos.back().X(), _pos.back().Y() );
+
+ if ( eos.SWOLType() != TopAbs_EDGE ) // wrong call
+ 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();
+ 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();
+
+ return gp_XY( 1e100, 1e100 );
+}
+
+//================================================================================
+/*!
+ * \brief Test intersection of the last segment with a given triangle
+ * using Moller-Trumbore algorithm
+ * Intersection is detected if distance to intersection is less than _LayerEdge._len
+ */
+//================================================================================
+
+bool _LayerEdge::SegTriaInter( const gp_Ax1& lastSegment,
+ const gp_XYZ& vert0,
+ const gp_XYZ& vert1,
+ const gp_XYZ& vert2,
+ double& t,
+ const double& EPSILON) const
+{
+ const gp_Pnt& orig = lastSegment.Location();
+ const gp_Dir& dir = lastSegment.Direction();
+
+ /* calculate distance from vert0 to ray origin */
+ gp_XYZ tvec = orig.XYZ() - vert0;
+
+ //if ( tvec * dir > EPSILON )
+ // intersected face is at back side of the temporary face this _LayerEdge belongs to
+ //return false;
+
+ gp_XYZ edge1 = vert1 - vert0;
+ gp_XYZ edge2 = vert2 - vert0;
+
+ /* begin calculating determinant - also used to calculate U parameter */
+ gp_XYZ pvec = dir.XYZ() ^ edge2;
+
+ /* if determinant is near zero, ray lies in plane of triangle */
+ double det = edge1 * pvec;
+
+ const double ANGL_EPSILON = 1e-12;
+ if ( det > -ANGL_EPSILON && det < ANGL_EPSILON )
+ return false;
+
+ /* calculate U parameter and test bounds */
+ double u = ( tvec * pvec ) / det;
+ //if (u < 0.0 || u > 1.0)
+ if ( u < -EPSILON || u > 1.0 + EPSILON )
+ return false;
+
+ /* prepare to test V parameter */
+ gp_XYZ qvec = tvec ^ edge1;
+
+ /* calculate V parameter and test bounds */
+ double v = (dir.XYZ() * qvec) / det;
+ //if ( v < 0.0 || u + v > 1.0 )
+ if ( v < -EPSILON || u + v > 1.0 + EPSILON )
+ return false;
+
+ /* calculate t, ray intersects triangle */
+ t = (edge2 * qvec) / det;
+
+ //return true;
+ return t > 0.;
+}
+
+//================================================================================
+/*!
+ * \brief _LayerEdge, located at a concave VERTEX of a FACE, moves target nodes of
+ * neighbor _LayerEdge's by it's own inflation vector.
+ * \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
+ */
+//================================================================================
+
+void _LayerEdge::MoveNearConcaVer( const _EdgesOnShape* eov,
+ const _EdgesOnShape* eos,
+ const int step,
+ vector< _LayerEdge* > & badSmooEdges )
+{
+ // check if any of _neibors is in badSmooEdges
+ if ( std::find_first_of( _neibors.begin(), _neibors.end(),
+ badSmooEdges.begin(), badSmooEdges.end() ) == _neibors.end() )
+ return;
+
+ // get all edges to move
+
+ set< _LayerEdge* > edges;
+
+ // find a distance between _LayerEdge on VERTEX and its neighbors
+ gp_XYZ curPosV = SMESH_TNodeXYZ( _nodes.back() );
+ double dist2 = 0;
+ for ( size_t i = 0; i < _neibors.size(); ++i )
+ {
+ _LayerEdge* nEdge = _neibors[i];
+ if ( nEdge->_nodes[0]->getshapeId() == eos->_shapeID )
+ {
+ edges.insert( nEdge );
+ dist2 = Max( dist2, ( curPosV - nEdge->_pos.back() ).SquareModulus() );
+ }
+ }
+ // add _LayerEdge's close to curPosV
+ size_t nbE;
+ do {
+ nbE = edges.size();
+ for ( set< _LayerEdge* >::iterator e = edges.begin(); e != edges.end(); ++e )
+ {
+ _LayerEdge* edgeF = *e;
+ for ( size_t i = 0; i < edgeF->_neibors.size(); ++i )
+ {
+ _LayerEdge* nEdge = edgeF->_neibors[i];
+ if ( nEdge->_nodes[0]->getshapeId() == eos->_shapeID &&
+ dist2 > ( curPosV - nEdge->_pos.back() ).SquareModulus() )
+ edges.insert( nEdge );
+ }
+ }
+ }
+ while ( nbE < edges.size() );
+
+ // move the target node of the got edges
+
+ gp_XYZ prevPosV = PrevPos();
+ if ( eov->SWOLType() == TopAbs_EDGE )
+ {
+ BRepAdaptor_Curve curve ( TopoDS::Edge( eov->_sWOL ));
+ prevPosV = curve.Value( prevPosV.X() ).XYZ();
+ }
+ else if ( eov->SWOLType() == TopAbs_FACE )
+ {
+ BRepAdaptor_Surface surface( TopoDS::Face( eov->_sWOL ));
+ prevPosV = surface.Value( prevPosV.X(), prevPosV.Y() ).XYZ();
+ }
+
+ SMDS_FacePosition* fPos;
+ //double r = 1. - Min( 0.9, step / 10. );
+ for ( set< _LayerEdge* >::iterator e = edges.begin(); e != edges.end(); ++e )
+ {
+ _LayerEdge* edgeF = *e;
+ const gp_XYZ prevVF = edgeF->PrevPos() - prevPosV;
+ const gp_XYZ newPosF = curPosV + prevVF;
+ SMDS_MeshNode* tgtNodeF = const_cast<SMDS_MeshNode*>( edgeF->_nodes.back() );
+ tgtNodeF->setXYZ( newPosF.X(), newPosF.Y(), newPosF.Z() );
+ edgeF->_pos.back() = newPosF;
+ dumpMoveComm( tgtNodeF, "MoveNearConcaVer" ); // debug
+
+ // set _curvature to make edgeF updated by putOnOffsetSurface()
+ if ( !edgeF->_curvature )
+ if (( fPos = dynamic_cast<SMDS_FacePosition*>( edgeF->_nodes[0]->GetPosition() )))
+ {
+ edgeF->_curvature = new _Curvature;
+ edgeF->_curvature->_r = 0;
+ edgeF->_curvature->_k = 0;
+ edgeF->_curvature->_h2lenRatio = 0;
+ edgeF->_curvature->_uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
+ }
+ }
+ // gp_XYZ inflationVec( SMESH_TNodeXYZ( _nodes.back() ) -
+ // SMESH_TNodeXYZ( _nodes[0] ));
+ // for ( set< _LayerEdge* >::iterator e = edges.begin(); e != edges.end(); ++e )
+ // {
+ // _LayerEdge* edgeF = *e;
+ // gp_XYZ newPos = SMESH_TNodeXYZ( edgeF->_nodes[0] ) + inflationVec;
+ // SMDS_MeshNode* tgtNode = const_cast<SMDS_MeshNode*>( edgeF->_nodes.back() );
+ // tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() );
+ // edgeF->_pos.back() = newPosF;
+ // dumpMoveComm( tgtNode, "MoveNearConcaVer" ); // debug
+ // }
+
+ // smooth _LayerEdge's around moved nodes
+ //size_t nbBadBefore = badSmooEdges.size();
+ for ( set< _LayerEdge* >::iterator e = edges.begin(); e != edges.end(); ++e )
+ {
+ _LayerEdge* edgeF = *e;
+ for ( size_t j = 0; j < edgeF->_neibors.size(); ++j )
+ if ( edgeF->_neibors[j]->_nodes[0]->getshapeId() == eos->_shapeID )
+ //&& !edges.count( edgeF->_neibors[j] ))
+ {
+ _LayerEdge* edgeFN = edgeF->_neibors[j];
+ edgeFN->Unset( SMOOTHED );
+ int nbBad = edgeFN->Smooth( step, /*isConcaFace=*/true, /*findBest=*/true );
+ // if ( nbBad > 0 )
+ // {
+ // gp_XYZ newPos = SMESH_TNodeXYZ( edgeFN->_nodes[0] ) + inflationVec;
+ // const gp_XYZ& prevPos = edgeFN->_pos[ edgeFN->_pos.size()-2 ];
+ // int nbBadAfter = edgeFN->_simplices.size();
+ // double vol;
+ // for ( size_t iS = 0; iS < edgeFN->_simplices.size(); ++iS )
+ // {
+ // nbBadAfter -= edgeFN->_simplices[iS].IsForward( &prevPos, &newPos, vol );
+ // }
+ // if ( nbBadAfter <= nbBad )
+ // {
+ // SMDS_MeshNode* tgtNode = const_cast<SMDS_MeshNode*>( edgeFN->_nodes.back() );
+ // tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() );
+ // edgeF->_pos.back() = newPosF;
+ // dumpMoveComm( tgtNode, "MoveNearConcaVer 2" ); // debug
+ // nbBad = nbBadAfter;
+ // }
+ // }
+ if ( nbBad > 0 )
+ badSmooEdges.push_back( edgeFN );
+ }
+ }
+ // move a bit not smoothed around moved nodes
+ // for ( size_t i = nbBadBefore; i < badSmooEdges.size(); ++i )
+ // {
+ // _LayerEdge* edgeF = badSmooEdges[i];
+ // SMDS_MeshNode* tgtNode = const_cast<SMDS_MeshNode*>( edgeF->_nodes.back() );
+ // gp_XYZ newPos1 = SMESH_TNodeXYZ( edgeF->_nodes[0] ) + inflationVec;
+ // gp_XYZ newPos2 = 0.5 * ( newPos1 + SMESH_TNodeXYZ( tgtNode ));
+ // tgtNode->setXYZ( newPos2.X(), newPos2.Y(), newPos2.Z() );
+ // edgeF->_pos.back() = newPosF;
+ // dumpMoveComm( tgtNode, "MoveNearConcaVer 2" ); // debug
+ // }
+}
+
+//================================================================================
+/*!
+ * \brief Perform smooth of _LayerEdge's based on EDGE's
+ * \retval bool - true if node has been moved
+ */
+//================================================================================
+
+bool _LayerEdge::SmoothOnEdge(Handle(ShapeAnalysis_Surface)& surface,
+ const TopoDS_Face& F,
+ SMESH_MesherHelper& helper)
+{
+ ASSERT( IsOnEdge() );
+
+ SMDS_MeshNode* tgtNode = const_cast<SMDS_MeshNode*>( _nodes.back() );
+ SMESH_TNodeXYZ oldPos( tgtNode );
+ double dist01, distNewOld;
+
+ SMESH_TNodeXYZ p0( _2neibors->tgtNode(0));
+ SMESH_TNodeXYZ p1( _2neibors->tgtNode(1));
+ dist01 = p0.Distance( _2neibors->tgtNode(1) );
+
+ gp_Pnt newPos = p0 * _2neibors->_wgt[0] + p1 * _2neibors->_wgt[1];
+ double lenDelta = 0;
+ if ( _curvature )
+ {
+ //lenDelta = _curvature->lenDelta( _len );
+ lenDelta = _curvature->lenDeltaByDist( dist01 );
+ newPos.ChangeCoord() += _normal * lenDelta;
+ }
+
+ distNewOld = newPos.Distance( oldPos );
+
+ if ( F.IsNull() )
+ {
+ if ( _2neibors->_plnNorm )
+ {
+ // put newPos on the plane defined by source node and _plnNorm
+ gp_XYZ new2src = SMESH_TNodeXYZ( _nodes[0] ) - newPos.XYZ();
+ double new2srcProj = (*_2neibors->_plnNorm) * new2src;
+ newPos.ChangeCoord() += (*_2neibors->_plnNorm) * new2srcProj;
+ }
+ tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() );
+ _pos.back() = newPos.XYZ();
+ }
+ else
+ {
+ tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() );
+ gp_XY uv( Precision::Infinite(), 0 );
+ helper.CheckNodeUV( F, tgtNode, uv, 1e-10, /*force=*/true );
+ _pos.back().SetCoord( uv.X(), uv.Y(), 0 );
+
+ newPos = surface->Value( uv );
+ tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() );
+ }
+
+ // commented for IPAL0052478
+ // if ( _curvature && lenDelta < 0 )
+ // {
+ // gp_Pnt prevPos( _pos[ _pos.size()-2 ]);
+ // _len -= prevPos.Distance( oldPos );
+ // _len += prevPos.Distance( newPos );
+ // }
+ bool moved = distNewOld > dist01/50;
+ //if ( moved )
+ dumpMove( tgtNode ); // debug
+
+ return moved;
+}
+
+//================================================================================
+/*!
+ * \brief Perform 3D smooth of nodes inflated from FACE. No check of validity
+ */
+//================================================================================
+
+void _LayerEdge::SmoothWoCheck()
+{
+ if ( Is( DIFFICULT ))
+ return;
+
+ bool moved = Is( SMOOTHED );
+ for ( size_t i = 0; i < _neibors.size() && !moved; ++i )
+ moved = _neibors[i]->Is( SMOOTHED );
+ if ( !moved )
+ return;
+
+ gp_XYZ newPos = (this->*_smooFunction)(); // fun chosen by ChooseSmooFunction()
+
+ SMDS_MeshNode* n = const_cast< SMDS_MeshNode* >( _nodes.back() );
+ n->setXYZ( newPos.X(), newPos.Y(), newPos.Z());
+ _pos.back() = newPos;
+
+ dumpMoveComm( n, SMESH_Comment("No check - ") << _funNames[ smooFunID() ]);
+}
+
+//================================================================================
+/*!
+ * \brief Checks validity of _neibors on EDGEs and VERTEXes
+ */
+//================================================================================
+
+int _LayerEdge::CheckNeiborsOnBoundary( vector< _LayerEdge* >* badNeibors )
+{
+ if ( ! Is( NEAR_BOUNDARY ))
+ return 0;
+
+ int nbBad = 0;
+ double vol;
+ for ( size_t iN = 0; iN < _neibors.size(); ++iN )
+ {
+ _LayerEdge* eN = _neibors[iN];
+ if ( eN->_nodes[0]->getshapeId() == _nodes[0]->getshapeId() )
+ continue;
+ SMESH_TNodeXYZ curPosN ( eN->_nodes.back() );
+ SMESH_TNodeXYZ prevPosN( eN->_nodes[0] );
+ for ( size_t i = 0; i < eN->_simplices.size(); ++i )
+ if ( eN->_nodes.size() > 1 &&
+ eN->_simplices[i].Includes( _nodes.back() ) &&
+ !eN->_simplices[i].IsForward( &prevPosN, &curPosN, vol ))
+ {
+ ++nbBad;
+ if ( badNeibors )
+ {
+ badNeibors->push_back( eN );
+ debugMsg("Bad boundary simplex ( "
+ << " "<< eN->_nodes[0]->GetID()
+ << " "<< eN->_nodes.back()->GetID()
+ << " "<< eN->_simplices[i]._nPrev->GetID()
+ << " "<< eN->_simplices[i]._nNext->GetID() << " )" );
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ return nbBad;
+}
+
+//================================================================================
+/*!
+ * \brief Perform 'smart' 3D smooth of nodes inflated from FACE
+ * \retval int - nb of bad simplices around this _LayerEdge
+ */
+//================================================================================
+
+int _LayerEdge::Smooth(const int step, bool findBest, vector< _LayerEdge* >& toSmooth )
+{
+ if ( !Is( MOVED ) || Is( SMOOTHED ))
+ return 0; // shape of simplices not changed
+ if ( _simplices.size() < 2 )
+ return 0; // _LayerEdge inflated along EDGE or FACE
+
+ if ( Is( DIFFICULT )) // || Is( ON_CONCAVE_FACE )
+ findBest = true;
+
+ const gp_XYZ& curPos = _pos.back();
+ const gp_XYZ& prevPos = PrevCheckPos();
+
+ // quality metrics (orientation) of tetras around _tgtNode
+ int nbOkBefore = 0;
+ double vol, minVolBefore = 1e100;
+ for ( size_t i = 0; i < _simplices.size(); ++i )
+ {
+ nbOkBefore += _simplices[i].IsForward( &prevPos, &curPos, vol );
+ minVolBefore = Min( minVolBefore, vol );
+ }
+ int nbBad = _simplices.size() - nbOkBefore;
+
+ if ( nbBad == 0 )
+ nbBad = CheckNeiborsOnBoundary();
+ if ( nbBad > 0 )
+ Set( DISTORTED );
+
+ // evaluate min angle
+ if ( nbBad == 0 && !findBest )
+ {
+ size_t nbGoodAngles = _simplices.size();
+ double angle;
+ for ( size_t i = 0; i < _simplices.size(); ++i )
+ {
+ if ( !_simplices[i].IsMinAngleOK( curPos, angle ) && angle > _minAngle )
+ --nbGoodAngles;
+ }
+ if ( nbGoodAngles == _simplices.size() )
+ {
+ Unset( MOVED );
+ return 0;
+ }
+ }
+ if ( Is( ON_CONCAVE_FACE ))
+ findBest = true;
+
+ if ( step % 2 == 0 )
+ findBest = false;
+
+ if ( Is( ON_CONCAVE_FACE ) && !findBest ) // alternate FUN_CENTROIDAL and FUN_LAPLACIAN
+ {
+ if ( _smooFunction == _funs[ FUN_LAPLACIAN ] )
+ _smooFunction = _funs[ FUN_CENTROIDAL ];
+ else
+ _smooFunction = _funs[ FUN_LAPLACIAN ];
+ }
+
+ // compute new position for the last _pos using different _funs
+ gp_XYZ newPos;
+ bool moved = false;
+ for ( int iFun = -1; iFun < theNbSmooFuns; ++iFun )
+ {
+ if ( iFun < 0 )
+ newPos = (this->*_smooFunction)(); // fun chosen by ChooseSmooFunction()
+ else if ( _funs[ iFun ] == _smooFunction )
+ continue; // _smooFunction again
+ else if ( step > 1 )
+ newPos = (this->*_funs[ iFun ])(); // try other smoothing fun
+ else
+ break; // let "easy" functions improve elements around distorted ones
+
+ if ( _curvature )