+//=======================================================================
+//function : CheckNodeU
+//purpose : Check and fix node U on an edge
+// Return false if U is bad and could not be fixed
+//=======================================================================
+
+bool SMESH_MesherHelper::CheckNodeU(const TopoDS_Edge& E,
+ const SMDS_MeshNode* n,
+ double& u,
+ const double tol,
+ const bool force,
+ double distXYZ[4]) const
+{
+ int shapeID = n->getshapeId();
+ if ( force || toCheckPosOnShape( shapeID ))
+ {
+ TopLoc_Location loc; double f,l;
+ Handle(Geom_Curve) curve = BRep_Tool::Curve( E,loc,f,l );
+ if ( curve.IsNull() ) // degenerated edge
+ {
+ if ( u+tol < f || u-tol > l )
+ {
+ double r = Max( 0.5, 1 - tol*n->GetID()); // to get a unique u on edge
+ u = f*r + l*(1-r);
+ }
+ }
+ else
+ {
+ gp_Pnt nodePnt = SMESH_TNodeXYZ( n );
+ if ( !loc.IsIdentity() ) nodePnt.Transform( loc.Transformation().Inverted() );
+ gp_Pnt curvPnt = curve->Value( u );
+ double dist = nodePnt.Distance( curvPnt );
+ if ( distXYZ ) {
+ curvPnt.Transform( loc );
+ distXYZ[0] = dist;
+ distXYZ[1] = curvPnt.X(); distXYZ[2] = curvPnt.Y(); distXYZ[3]=curvPnt.Z();
+ }
+ if ( dist > tol )
+ {
+ setPosOnShapeValidity( shapeID, false );
+ // u incorrect, project the node to the curve
+ int edgeID = GetMeshDS()->ShapeToIndex( E );
+ TID2ProjectorOnCurve& i2proj = const_cast< TID2ProjectorOnCurve&>( myEdge2Projector );
+ TID2ProjectorOnCurve::iterator i_proj =
+ i2proj.insert( make_pair( edgeID, (GeomAPI_ProjectPointOnCurve*) 0 )).first;
+ if ( !i_proj->second )
+ {
+ i_proj->second = new GeomAPI_ProjectPointOnCurve();
+ i_proj->second->Init( curve, f, l );
+ }
+ GeomAPI_ProjectPointOnCurve* projector = i_proj->second;
+ projector->Perform( nodePnt );
+ if ( projector->NbPoints() < 1 )
+ {
+ MESSAGE( "SMESH_MesherHelper::CheckNodeU() failed to project" );
+ return false;
+ }
+ Quantity_Parameter U = projector->LowerDistanceParameter();
+ u = double( U );
+ curvPnt = curve->Value( u );
+ dist = nodePnt.Distance( curvPnt );
+ if ( distXYZ ) {
+ curvPnt.Transform( loc );
+ distXYZ[0] = dist;
+ distXYZ[1] = curvPnt.X(); distXYZ[2] = curvPnt.Y(); distXYZ[3]=curvPnt.Z();
+ }
+ if ( dist > tol )
+ {
+ MESSAGE( "SMESH_MesherHelper::CheckNodeU(), invalid projection" );
+ MESSAGE("distance " << dist << " " << tol );
+ return false;
+ }
+ // store the fixed U on the edge
+ if ( myShape.IsSame(E) && shapeID == myShapeID )
+ const_cast<SMDS_MeshNode*>(n)->SetPosition
+ ( SMDS_PositionPtr( new SMDS_EdgePosition( U )));
+ }
+ else if ( fabs( u ) > numeric_limits<double>::min() )
+ {
+ setPosOnShapeValidity( shapeID, true );
+ }
+ if (( u < f-tol || u > l+tol ) && force )
+ {
+ // node is on vertex but is set on periodic but trimmed edge (issue 0020890)
+ try
+ {
+ // do not use IsPeriodic() as Geom_TrimmedCurve::IsPeriodic () returns false
+ double period = curve->Period();
+ u = ( u < f ) ? u + period : u - period;
+ }
+ catch (Standard_Failure& exc)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+//=======================================================================
+//function : GetMediumNode
+//purpose : Return existing or create new medium nodes between given ones
+//=======================================================================