+//function : CheckNodeUV
+//purpose : Check and fix node UV on a face
+//=======================================================================
+
+bool SMESH_MesherHelper::CheckNodeUV(const TopoDS_Face& F,
+ const SMDS_MeshNode* n,
+ gp_XY& uv,
+ const double tol,
+ const bool force) const
+{
+ if ( force || !myOkNodePosShapes.count( n->GetPosition()->GetShapeId() ))
+ {
+ // check that uv is correct
+ TopLoc_Location loc;
+ Handle(Geom_Surface) surface = BRep_Tool::Surface( F,loc );
+ gp_Pnt nodePnt = XYZ( n );
+ if ( !loc.IsIdentity() ) nodePnt.Transform( loc.Transformation().Inverted() );
+ if ( Precision::IsInfinite( uv.X() ) ||
+ Precision::IsInfinite( uv.Y() ) ||
+ nodePnt.Distance( surface->Value( uv.X(), uv.Y() )) > tol )
+ {
+ // uv incorrect, project the node to surface
+ GeomAPI_ProjectPointOnSurf projector( nodePnt, surface, tol );
+ if ( !projector.IsDone() || projector.NbPoints() < 1 )
+ {
+ MESSAGE( "SMESH_MesherHelper::CheckNodeUV() failed to project" );
+ return false;
+ }
+ Quantity_Parameter U,V;
+ projector.LowerDistanceParameters(U,V);
+ if ( nodePnt.Distance( surface->Value( U, V )) > tol )
+ {
+ MESSAGE( "SMESH_MesherHelper::CheckNodeUV(), invalid projection" );
+ return false;
+ }
+ uv.SetCoord( U,V );
+ }
+ else if ( uv.Modulus() > numeric_limits<double>::min() )
+ {
+ ((SMESH_MesherHelper*) this)->myOkNodePosShapes.insert( n->GetPosition()->GetShapeId() );
+ }
+ }
+ return true;
+}
+
+namespace
+{
+ struct TMiddle
+ {
+ gp_XY operator()(const gp_XY& uv1, const gp_XY& uv2) const { return ( uv1 + uv2 ) / 2.; }
+ };
+ struct TAdd
+ {
+ gp_XY operator()(const gp_XY& uv1, const gp_XY& uv2) const { return ( uv1 + uv2 ); }
+ };
+ struct TSubtract
+ {
+ gp_XY operator()(const gp_XY& uv1, const gp_XY& uv2) const { return ( uv1 - uv2 ); }
+ };
+
+ //================================================================================
+ /*!
+ * \brief Perform given operation on two points in parametric space of given surface
+ * Example: gp_XY uvSum = applyXYFUN( surf, uv1, uv2, gp_XYFun(Added))
+ */
+ //================================================================================
+
+ template<typename FUNC>
+ gp_XY applyFunc(const Handle(Geom_Surface)& surface,
+ const gp_XY& uv1,
+ gp_XY uv2,
+ const bool resultInPeriod=true)
+ {
+ Standard_Boolean isUPeriodic = surface.IsNull() ? false : surface->IsUPeriodic();
+ Standard_Boolean isVPeriodic = surface.IsNull() ? false : surface->IsVPeriodic();
+ if ( !isUPeriodic && !isVPeriodic )
+ return FUNC()(uv1,uv2);
+
+ // move uv2 not far than half-period from uv1
+ if ( isUPeriodic )
+ uv2.SetX( uv2.X()+ShapeAnalysis::AdjustByPeriod(uv2.X(),uv1.X(),surface->UPeriod()) );
+ if ( isVPeriodic )
+ uv2.SetY( uv2.Y()+ShapeAnalysis::AdjustByPeriod(uv2.Y(),uv1.Y(),surface->VPeriod()) );
+
+ // execute operation
+ gp_XY res = FUNC()(uv1,uv2);
+
+ // move result within period
+ if ( resultInPeriod )
+ {
+ Standard_Real UF,UL,VF,VL;
+ surface->Bounds(UF,UL,VF,VL);
+ if ( isUPeriodic )
+ res.SetX( res.X() + ShapeAnalysis::AdjustToPeriod(res.X(),UF,UL));
+ if ( isVPeriodic )
+ res.SetY( res.Y() + ShapeAnalysis::AdjustToPeriod(res.Y(),VF,VL));
+ }
+
+ return res;
+ }
+}
+//=======================================================================
+//function : GetMiddleUV
+//purpose : Return middle UV taking in account surface period