//:r5 abv 06.04.99: ec_turbine-A.stp, #4313: protect against null curve
//    abv 09.04.99  S4136: add parameter preci (to eliminate BRepAPI::Precision)
#include <ShapeFix_EdgeProjAux.ixx>

#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>

#include <ElCLib.hxx>

#include <Adaptor3d_CurveOnSurface.hxx>
#include <Geom2dAdaptor_Curve.hxx>
#include <Geom2dAdaptor_HCurve.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomAdaptor_HSurface.hxx>

#include <Geom2d_Curve.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <Geom2d_Line.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Surface.hxx> 
#include <Geom_SphericalSurface.hxx>

#include <BRep_Tool.hxx>
#include <Precision.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopExp.hxx>

#include <ShapeAnalysis.hxx>
#include <ShapeAnalysis_Curve.hxx>
#include <ShapeAnalysis_Edge.hxx>
#include <ShapeAnalysis_Surface.hxx>

#include <Extrema_ExtPC.hxx>
#include <gp_Pnt.hxx>

//=======================================================================
//function : ShapeFix_EdgeProjAux
//purpose  : 
//=======================================================================

ShapeFix_EdgeProjAux::ShapeFix_EdgeProjAux ()
{
  myFirstDone = myLastDone = Standard_False;
}

//=======================================================================
//function : ShapeFix_EdgeProjAux
//purpose  : 
//=======================================================================

ShapeFix_EdgeProjAux::ShapeFix_EdgeProjAux (const TopoDS_Face& F,
                                            const TopoDS_Edge& E)
{
  Init (F, E);
}

//=======================================================================
//function : Init
//purpose  : 
//=======================================================================

void ShapeFix_EdgeProjAux::Init (const TopoDS_Face& F,
                                 const TopoDS_Edge& E)
{
  myFace = F;
  myEdge = E;
  myFirstDone = myLastDone = Standard_False;
}

//=======================================================================
//function : Compute
//purpose  : 
//=======================================================================

void ShapeFix_EdgeProjAux::Compute (const Standard_Real preci) 
{
  myFirstDone = myLastDone = Standard_False;
    
  // Project Point3d on Surface
  // TEMPORARY Call ShapeFix_EdgeProjAux

  Init2d(preci);
  if (IsFirstDone() && IsLastDone()) {
    Standard_Real U1 = FirstParam();
    Standard_Real U2 = LastParam();
    if (U1>=U2) {
#ifdef DEBUG
      cout << "Parametres inverses ... " << endl;
#endif
      Standard_Real tmp = U1;
      U1 = U2; U2 = tmp;
    }
    myFirstParam = U1;
    myFirstDone  = Standard_True;
    myLastParam  = U2;
    myLastDone   = Standard_True;
  }
}

//=======================================================================
//function : IsFirstDone
//purpose  : 
//=======================================================================

Standard_Boolean ShapeFix_EdgeProjAux::IsFirstDone() const
{
  return myFirstDone;
}

//=======================================================================
//function : IsLastDone
//purpose  : 
//=======================================================================

Standard_Boolean ShapeFix_EdgeProjAux::IsLastDone() const
{
  return myLastDone;
}

//=======================================================================
//function : FirstParam
//purpose  : 
//=======================================================================

Standard_Real ShapeFix_EdgeProjAux::FirstParam() const
{
  return myFirstParam;
}

//=======================================================================
//function : LastParam
//purpose  : 
//=======================================================================

Standard_Real ShapeFix_EdgeProjAux::LastParam() const
{
  return myLastParam;
}

//=======================================================================
//function : IsIso
//purpose  : 
//=======================================================================

Standard_Boolean ShapeFix_EdgeProjAux::IsIso (const Handle(Geom2d_Curve)& /*theCurve2d*/)
{
  // Until an ISO is recognized by Adaptor3d_Curve
/*  
  if (theCurve2d->IsKind(STANDARD_TYPE(Geom2d_Line))) {
    Handle(Geom2d_Line) theLine2d = Handle(Geom2d_Line)::DownCast(theCurve2d);
    gp_Dir2d theDir2d = theLine2d->Direction();
    
    gp_Dir2d dir1(0.,1.);
    gp_Dir2d dir2(0.,-1.);
    
    return (theDir2d.IsEqual(dir1,Precision::Angular()) ||
	    theDir2d.IsEqual(dir2,Precision::Angular()) ||
	    theDir2d.IsNormal(dir1,Precision::Angular()) ||
	    theDir2d.IsNormal(dir2,Precision::Angular()) );
  }
*/
  return Standard_False;
}

// ----------------------------------------------------------------------------
// static  : FindParameterWithExt
// Purpose : Computes the trimming parameter of Pt1 on COnS
// ----------------------------------------------------------------------------

static Standard_Boolean FindParameterWithExt (const gp_Pnt& Pt1, 
					      const Adaptor3d_CurveOnSurface& COnS,
					      const Standard_Real Uinf,
					      const Standard_Real Usup, 
					      const Standard_Real preci,
					      Standard_Real& w1)
{
  try {  // et allez donc !
    OCC_CATCH_SIGNALS
    Extrema_ExtPC myExtPC (Pt1, COnS, Uinf, Usup, preci);

    //ShapeFix_ExtPCOnS myExtPCOnS1 = 
    //ShapeFix_ExtPCOnS(Pt1, COnS, Uinf, Usup, preci);
  
    if (myExtPC.IsDone()) {
      Standard_Integer NbExt1 = myExtPC.NbExt();
      for (Standard_Integer i=1; i<=NbExt1; i++) {
	if (myExtPC.IsMin(i)) {
	  //Standard_Real dist = myExtPC.Value(i); //szv#4:S4163:12Mar99 debug mode only
	  w1   = myExtPC.Point(i).Parameter();
	}
      }
      return Standard_True;
    }
    else return Standard_False;
  }  // end try
  catch(Standard_Failure) {
//     MoniTool_DB& dbl = MoniTool_DB::Cur();
//     dbl.Add("EdgeProjAux::FindParameterWithExt");
//     dbl.AddRaised();
//     dbl.AddXYZ  (Pt1.XYZ());
//     dbl.AddReals(Uinf,Usup);
//    dbl.AddGeom (theSurf);  que peut-on enregistrer ?
#ifdef DEB //:s5
    cout << "Warning: ShapeFix_EdgeProjAux, FindParameterWithExt(): Exception: ";
    Standard_Failure::Caught()->Print(cout); cout << endl;
#endif
    return Standard_False;
  }
  return Standard_False;  // normalement, on n y passe jamais
}

//=======================================================================
//function : Init2d
//purpose  : 
//=======================================================================

void ShapeFix_EdgeProjAux::Init2d (const Standard_Real preci) 
{
  Standard_Real cl, cf;

  // Extract Geometries
  Handle(Geom_Surface) theSurface = BRep_Tool::Surface(myFace);
  Handle(Geom2d_Curve) theCurve2d = BRep_Tool::CurveOnSurface(myEdge, myFace, cf, cl);
  if ( theCurve2d.IsNull() ) return; //:r5 abv 6 Apr 99:  ec_turbine-A.stp, #4313

  TopoDS_Vertex V1,V2;
  TopExp::Vertices(myEdge, V1, V2);
  gp_Pnt Pt1,Pt2;
  // pdn 28.12.98: r_39-db.stp #605: use ends of 3d curve instead of vertices 
  ShapeAnalysis_Edge sae;
  Standard_Real a,b;
  Handle(Geom_Curve) C3d;
  if(sae.Curve3d(myEdge,C3d,a,b,Standard_False)) {
    Pt1 = C3d->Value(a);
    Pt2 = C3d->Value(b);
  } 
  else {
    Pt1 = BRep_Tool::Pnt(V1);
    Pt2 = BRep_Tool::Pnt(V2);
  }
//:S4136  Standard_Real preci = BRepAPI::Precision();
  //pdn to manage degenerated case
  if (V1.IsSame(V2)) {
    Handle(ShapeAnalysis_Surface) stsu = new ShapeAnalysis_Surface (theSurface);
    gp_Pnt2d aPt1,aPt2;
    Standard_Real firstpar,lastpar;
    if (stsu->DegeneratedValues(Pt1,preci,aPt1,aPt2,firstpar,lastpar)){
      
      if(theCurve2d->IsKind(STANDARD_TYPE(Geom2d_Line))) {
	if (aPt1.IsEqual(theCurve2d->Value(firstpar),preci) && 
	    aPt2.IsEqual(theCurve2d->Value(lastpar),preci)){
	  myFirstParam = firstpar;
	  myLastParam  = lastpar;
	  myFirstDone = myLastDone = Standard_True;
	  return;
	}
      } 
#ifdef DEBUG
      else cout <<"Other type of deg curve"<<endl;
#endif
      
    }
  }
  
  Standard_Boolean parU = Standard_False, parV = Standard_False;
  GeomAdaptor_Surface          SA     = GeomAdaptor_Surface(theSurface);
  Handle(GeomAdaptor_HSurface) myHSur = new GeomAdaptor_HSurface(SA);
  
  cf = theCurve2d->FirstParameter();
  cl = theCurve2d->LastParameter();
  //pdn cutting pcurve by suface bounds
  if (Precision::IsInfinite(cf)||Precision::IsInfinite(cf)) {
    if(theCurve2d->IsKind(STANDARD_TYPE(Geom2d_Line))) {
      Standard_Real uf,ul,vf,vl;
      theSurface->Bounds(uf,ul,vf,vl);
      if(!Precision::IsInfinite(uf)&&!Precision::IsInfinite(ul)&&
	 !Precision::IsInfinite(vf)&&!Precision::IsInfinite(vl)) {
	Standard_Real cfi,cli;
	Handle(Geom2d_Line) lin = Handle(Geom2d_Line)::DownCast(theCurve2d);
	gp_Pnt2d pnt = lin->Location();
	gp_Dir2d dir = lin->Direction();
	if (dir.Y()==0) {
	  parU = Standard_True;
	  cfi = (uf-pnt.X())/dir.X();
	  cli = (ul-pnt.X())/dir.X();
	} 
	else if (dir.X()==0) {
	  parV = Standard_True;
	  cfi = (vf-pnt.Y())/dir.Y();
	  cli = (vl-pnt.Y())/dir.Y();
	} 
	else {//common case
	  Standard_Real xfi, xli, yfi, yli;
	  xfi = (uf-pnt.X())/dir.X();
	  xli = (ul-pnt.X())/dir.X();
	  yfi = (vf-pnt.Y())/dir.Y();
	  yli = (vl-pnt.Y())/dir.Y();
	  if (dir.X()*dir.Y() > 0) {
	    cfi = (Abs(xli-xfi) < Abs(xli-yfi)? xfi : yfi);
	    cli = (Abs(xfi-xli) < Abs(xfi-yli)? xli : yli);
	  } else {
	    cfi = (Abs(xli-xfi) < Abs(xli-yli)? xfi : yli);
	    cli = (Abs(yli-xli) < Abs(yli-yfi)? xli : yfi);
	  }
	}
	if (cfi < cli) { cf = cfi; cl = cli; }
	else { cf = cli; cl = cfi; }
      } 
      else if(!Precision::IsInfinite(uf)&&!Precision::IsInfinite(ul)){
	Handle(Geom2d_Line) lin = Handle(Geom2d_Line)::DownCast(theCurve2d);
	gp_Dir2d dir = lin->Direction();
	if (dir.X()!=0) {
	  if (dir.Y()==0) parU = Standard_True;
	  gp_Pnt2d pnt = lin->Location(); //szv#4:S4163:12Mar99 moved
	  Standard_Real cfi = (uf-pnt.X())/dir.X();
	  Standard_Real cli = (ul-pnt.X())/dir.X();
	  if (cfi < cli) { cf = cfi; cl = cli; }
	  else { cf = cli; cl = cfi; }
	}
	else {
	  cf=-10000;
	  cl= 10000;
	}
      }
      else {
	cf=-10000;
	cl= 10000;
	//pdn not cutted by bounds
#ifdef DEBUG
	cout<<"Infinite Surface"<<endl;
#endif	
      }
    }
    else {
      //pdn not linear case not managed
      cf=-10000;
      cl= 10000;
#ifdef DEBUG     
      cout<<"Some infinite curve"<<endl;
#endif 
    }
  }
  
  Geom2dAdaptor_Curve          CA     = Geom2dAdaptor_Curve(theCurve2d,cf,cl);
  Handle(Geom2dAdaptor_HCurve) myHCur = new Geom2dAdaptor_HCurve(CA);
  
  Adaptor3d_CurveOnSurface COnS = Adaptor3d_CurveOnSurface(myHCur, myHSur);

  // ----------------------------------------------
  // --- topological limit == geometric limit ? ---
  // ----------------------------------------------
  Standard_Real Uinf = COnS.FirstParameter();
  Standard_Real Usup = COnS.LastParameter();
  
  Standard_Real w1,w2;
  ShapeAnalysis_Curve sac;
  gp_Pnt pnt;
  Standard_Real dist = sac.Project(COnS,Pt1,preci,pnt,w1,Standard_False);
  if (dist > preci) return;
  dist = sac.Project(COnS,Pt2,preci,pnt,w2,Standard_False);
  if (dist > preci) return;
  
  myFirstParam = w1;
  myLastParam  = w2;
  myFirstDone = myLastDone = Standard_True;
  if ( myFirstParam == Uinf && myLastParam == Usup ) return;
  if ( myFirstParam == Usup && myLastParam == Uinf ) {
    myFirstParam = theCurve2d->ReversedParameter(Usup);
    myLastParam  = theCurve2d->ReversedParameter(Uinf);
    theCurve2d->Reverse();
#ifdef DEB
    cout << "Warning: ShapeFix_EdgeProjAux: pcurve reversed" << endl;
#endif
    return;
  }
  //:abv 29.08.01: SAT: fix for closed case
  if ( COnS.Value(Uinf).Distance ( COnS.Value(Usup) ) < Precision::Confusion() ) {
    // 18.11.2002 SKL OCC630 compare values with tolerance Precision::PConfusion() instead of "=="
    if ( Abs(myFirstParam-Uinf) < ::Precision::PConfusion() &&
         Abs(myLastParam-Uinf) < ::Precision::PConfusion() )
        myLastParam = w2 = Usup;
    // 18.11.2002 SKL OCC630 compare values with tolerance Precision::PConfusion() instead of "=="
    else if ( Abs(myFirstParam-Usup) < ::Precision::PConfusion() && 
              Abs(myLastParam-Usup) < ::Precision::PConfusion() )
        myFirstParam = w1 = Uinf;
  }
   
  //pdn adjust parameters in periodic case
  if(parU || parV) {
    Standard_Real uf,ul,vf,vl;
    theSurface->Bounds(uf,ul,vf,vl);
    Standard_Real period = (parU ? ul-uf : vl-vf);
    w1+=ShapeAnalysis::AdjustToPeriod(w1,0,period);
    myFirstParam = w1;
    w2+=ShapeAnalysis::AdjustToPeriod(w2,0,period);
    myLastParam = w2;
    Handle(Geom_Curve) C3d1;
    if(!sae.Curve3d (myEdge, C3d1, cf, cl, Standard_False )) {
      UpdateParam2d(theCurve2d);
      return;
    }
    gp_Pnt mid = C3d1->Value((cf+cl)/2);
    Standard_Real wmid;
    sac.Project(COnS,mid,preci,pnt,wmid,Standard_False);
    wmid+=ShapeAnalysis::AdjustToPeriod(wmid,0,period);
    if(w1>w2) {
      if(w2 > wmid) myFirstParam -= period;
      else if (w1 > wmid)
	UpdateParam2d(theCurve2d);
      else {
	myLastParam+=period;
#ifdef DEBUG
	cout <<" Added"<<endl;
#endif	
      }
    }
    else {
      if(w1 > wmid) {
	myLastParam -=period;
	UpdateParam2d(theCurve2d);
#ifdef DEBUG
	cout <<" Added & Inverted"<<endl;
#endif	
      } else if (w2 < wmid) {
	myFirstParam += period;
	UpdateParam2d(theCurve2d);
      }
    }
  }
  UpdateParam2d(theCurve2d);
  return;
}

//=======================================================================
//function : Init3d
//purpose  : 
//=======================================================================

void ShapeFix_EdgeProjAux::Init3d (const Standard_Real preci) 
{
  Standard_Real cl, cf;

  // Extract Geometries
  Handle(Geom_Surface) theSurface = BRep_Tool::Surface(myFace);
  Handle(Geom2d_Curve) theCurve2d = BRep_Tool::CurveOnSurface(myEdge, myFace, cf, cl);
  if ( theCurve2d.IsNull() ) return; //:r5 abv 6 Apr 99:  ec_turbine-A.stp, #4313
  TopoDS_Vertex V1,V2;
  
  V1 = TopExp::FirstVertex(myEdge);
  V2 = TopExp::LastVertex(myEdge);
  gp_Pnt Pt1 = BRep_Tool::Pnt(V1);
  gp_Pnt Pt2 = BRep_Tool::Pnt(V2);


  GeomAdaptor_Surface          SA     = GeomAdaptor_Surface(theSurface);  
  Handle(GeomAdaptor_HSurface) myHSur = new GeomAdaptor_HSurface(SA);

  Geom2dAdaptor_Curve          CA     = Geom2dAdaptor_Curve(theCurve2d);
  Handle(Geom2dAdaptor_HCurve) myHCur = new Geom2dAdaptor_HCurve(CA);

  Adaptor3d_CurveOnSurface COnS = Adaptor3d_CurveOnSurface(myHCur, myHSur);
  
//:S4136  Standard_Real preci = BRepAPI::Precision();
  Standard_Real Uinf = theCurve2d->FirstParameter();
  Standard_Real Usup = theCurve2d->LastParameter();

  // ----------------------------------------------
  // --- topological limit == geometric limit ? ---
  // ----------------------------------------------
  
  if (theCurve2d->IsKind(STANDARD_TYPE(Geom2d_BoundedCurve))) {
    
    gp_Pnt Pdeb = COnS.Value(Uinf);
    gp_Pnt Pfin = COnS.Value(Usup);
    
    //szv#4:S4163:12Mar99 optimized
    if ( Pdeb.IsEqual(Pt1, preci) && Pfin.IsEqual(Pt2, preci) ) {
      myFirstParam = Uinf;
      myLastParam  = Usup;
      myFirstDone = myLastDone = Standard_True;
      return;
    }
  }

  // ------------------------------------------
  // --- The CurveOnSurface is not infinite ---
  // ---          Try with Extrema          ---
  // ------------------------------------------

  Standard_Real w1 = COnS.FirstParameter();
  Standard_Real w2 = COnS.LastParameter();

  if ((!Precision::IsInfinite(w1) &&
       !Precision::IsInfinite(w2) &&
       theCurve2d->Continuity() != GeomAbs_C0) ||
      IsIso(theCurve2d))  {

    //szv#4:S4163:12Mar99 optimized
    if ( FindParameterWithExt(Pt1, COnS, Uinf, Usup, preci, w1) &&
	 FindParameterWithExt(Pt2, COnS, Uinf, Usup, preci, w2) ) {
      myFirstParam = w1;
      myLastParam  = w2;
      UpdateParam2d(theCurve2d);
      myFirstDone = myLastDone = Standard_True;
      return;
    }
  }
  myFirstDone = myLastDone = Standard_True;
}

//=======================================================================
//function : UpdateParam2d
//purpose  : 
//=======================================================================

void ShapeFix_EdgeProjAux::UpdateParam2d (const Handle(Geom2d_Curve)& theCurve2d)
{
  if (myFirstParam < myLastParam)  return;

  Standard_Real cf = theCurve2d->FirstParameter();
  Standard_Real cl = theCurve2d->LastParameter();
//:S4136  Standard_Real preci = BRepAPI::Precision();
  Standard_Real preci2d = Precision::PConfusion(); //:S4136: Parametric(preci, 0.01);

  // 15.11.2002 PTV OCC966
  if (ShapeAnalysis_Curve::IsPeriodic(theCurve2d)) {
    ElCLib::AdjustPeriodic(cf,cl,preci2d,myFirstParam,myLastParam);
  }
  else if (theCurve2d->IsClosed()) {
    //szv#4:S4163:12Mar99 optimized
    if      ( Abs ( myFirstParam - cl ) <= preci2d ) myFirstParam = cf;
    else if ( Abs ( myLastParam  - cf ) <= preci2d ) myLastParam  = cl;
    else {
#ifdef DEBUG
      cout << "Error : curve 2d range crossing non periodic curve origin";
      cout <<  endl;
#endif
      // add fail result;
      return;
    }
  }
  // the curve is closed within the 'file' 2D tolerance 
  else if (theCurve2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) {
    Handle(Geom2d_BSplineCurve) aBSpline2d =
      Handle(Geom2d_BSplineCurve)::DownCast(theCurve2d);
    if (aBSpline2d->StartPoint().Distance(aBSpline2d->EndPoint()) <= preci2d) {
      if      ( Abs ( myFirstParam - cl ) <= preci2d ) myFirstParam = cf;
      else if ( Abs ( myLastParam  - cf ) <= preci2d ) myLastParam  = cl;
    }
  }
  else {
#ifdef DEBUG
    cout << "Warning : non increasing parameters for 2d curve." << endl;
    cout << "          update parameter 2d uncertain." << endl;
#endif
    Standard_Real tmp1 = myFirstParam, tmp2 = myLastParam;
    myFirstParam = theCurve2d->ReversedParameter(tmp1);
    myLastParam = theCurve2d->ReversedParameter(tmp2);
    theCurve2d->Reverse();
    //cout<<"Reversed case 2"<<endl;
  }
}

// ----------------------------------------------------------------------------
// static  : UpdateParam2d
// Purpose : for Init2d and Init3d
// ----------------------------------------------------------------------------
/*
static Standard_Boolean UpdateParam2d (const Handle(Geom2d_Curve)& theCurve2d, 
				       const Handle(Geom_Surface)& theSurface,
				       const gp_Pnt& Pt1,
				       const gp_Pnt& Pt2,
				       gp_Pnt2d& pt1, 
				       gp_Pnt2d& pt2,
				       Standard_Real& w1, 
				       Standard_Real& w2)
{
  if (w1 < w2) {
    return Standard_True;
  }

  Standard_Real iniW1 = w1;
  Standard_Real iniW2 = w2;

  Standard_Real ufirst, ulast, vfirst, vlast;
  theSurface->Bounds(ufirst, ulast, vfirst, vlast);
  Standard_Real ULength = ulast - ufirst;
  Standard_Real VLength = vlast - vfirst;
  
  if (theSurface->IsUClosed() &&
      theSurface->IsVClosed()) {
    
    Standard_Real u1 = pt1.X();
    Standard_Real u2 = pt2.X();
    Standard_Real v1 = pt1.Y();
    Standard_Real v2 = pt2.Y();
    
    // ---------------------------------
    // 1. Try U translation  of Vertex 1
    // ---------------------------------
    u1 = u1 - ULength;
    pt1.SetX(u1);
    ShapeFix_Curve2dAux aC2dAux;

    Standard_Boolean founded = 
      aC2dAux.IsPointOnCurve(pt1, theCurve2d, theSurface, w1);
    if (founded && (w1 < w2))
      return Standard_True;
    else {
      // reset initial w1
      w1 = iniW1;
      // ---------------------------------
      // 2. Try V translation  of Vertex 1
      // ---------------------------------
      v1 = v1 - VLength;
      u1 = u1 + ULength; // keep initial U coordinate
      pt1.SetY(v1);
      pt1.SetX(u1);
      Standard_Boolean founded = 
	aC2dAux.IsPointOnCurve(pt1, theCurve2d, theSurface, w1);
      if (founded && (w1 < w2))
	return Standard_True;
      else {
	// reset initial w1
	w1 = iniW1;
	// --------------------------------
	// 1. Try U translation of Vertex 2
	// --------------------------------
	u2 = u2 - ULength;
	pt2.SetX(u2);
	Standard_Boolean founded = 
	  aC2dAux.IsPointOnCurve(pt2, theCurve2d, theSurface, w2);
	if (founded && (w1 < w2))
	  return Standard_True;
	else {
	  // reset initial w2
	  w2 = iniW2;
	  // --------------------------------
	  // 2. Try V translation of Vertex 2
	  // --------------------------------
	  v2 = v2 - VLength;
	  u2 = u2 + ULength; // Keep initial U Coordinate
	  pt2.SetY(v2);
	  pt2.SetX(u2);
	  Standard_Boolean founded = 
	    aC2dAux.IsPointOnCurve(pt2, theCurve2d, theSurface, w2);
	  if (founded && (w1 < w2))
	    return Standard_True;
	  else { 
#ifdef DEBUG
	    cout << "later : +u+v -u-v ... " << endl;
#endif
	    return Standard_False;
	  }
	}
      }
    }
  }
  else if (theSurface->IsVClosed()) {
    
    Standard_Real v1 = pt1.Y();
    Standard_Real v2 = pt2.Y();
    
    // ---------------------------------
    // 1. Try V translation  of Vertex 2
    // ---------------------------------
    v1 = v1 - VLength;
    pt1.SetY(v1);
    ShapeFix_Curve2dAux aC2dAux;

    Standard_Boolean founded = 
      aC2dAux.IsPointOnCurve(pt1, theCurve2d, theSurface, w1);
    if (founded && (w1 < w2))
      return Standard_True;
    else {
      // reset initial w1
      w1 = iniW1;
      // ---------------------------------
      // 1. Try V translation  of Vertex 2
      // ---------------------------------
      v2 = v2 + VLength;
      pt2.SetY(v2);
      Standard_Boolean founded = 
	aC2dAux.IsPointOnCurve(pt2, theCurve2d, theSurface, w2);
      if (founded && (w1 < w2))
	return Standard_True;
      else
	return Standard_False;
    }
  }
  else if (theSurface->IsUClosed()) {
    
    Standard_Real u1 = pt1.X();
    Standard_Real u2 = pt2.X();
    
    // ---------------------------------
    // 1. Try U translation  of Vertex 1
    // ---------------------------------
    u1 = u1 - ULength;
    pt1.SetX(u1);
    ShapeFix_Curve2dAux aC2dAux;

    Standard_Boolean founded = 
      aC2dAux.IsPointOnCurve(pt1, theCurve2d, theSurface, w1);
    if (founded && (w1 < w2))
      return Standard_True;
    else {
      // reset initial w1
      w1 = iniW1;
      // ---------------------------------
      // 1. Try U translation  of Vertex 2
      // ---------------------------------
// **DTH** 19/5/95
// **DTH**      u2 = u2 - ULength;
      u2 = u2 + ULength;
      pt2.SetX(u2);
      Standard_Boolean founded = 
	aC2dAux.IsPointOnCurve(pt2, theCurve2d, theSurface, w2);
      if (founded && (w1 < w2))
	return Standard_True;
      else
	return Standard_False;
    }
  }
  else if (theCurve2d->IsPeriodic()) { // the curve is Periodic
    Standard_Real cf = theCurve2d->FirstParameter();
    Standard_Real cl = theCurve2d->LastParameter();
    Standard_Real preci = Precision::PConfusion(); //:S4136: BRepAPI::Precision(); // Bad -> 3d tolerance
    ElCLib::AdjustPeriodic(cf,cl,preci,w1,w2);
  }
  
  else { // the curve is not periodic nor closed, surface not closed
#ifdef DEBUG
    cout << "WARNING :The surface is not closed, curve not periodic nor closed..." << endl;
#endif
    return Standard_False;
  }
  return Standard_True;
}
*/

//=======================================================================
//function : IsPointOnCurve
// Purpose : If the point2d is not lying on the pcurve, update point2d 
//           Not yet implemented : Closed Non Periodic Surfaces ->
//           Take care about crossing the seam
//=======================================================================
/* //:S4136

Standard_Boolean ShapeFix_EdgeProjAux::IsPointOnCurve (const gp_Pnt2d& thePoint2d,
						      const Handle(Geom2d_Curve)& theCurve2d,
						      const Handle(Geom_Surface)& theSurface,
						      Standard_Real& theParam) 
{
  Standard_Real cl = theCurve2d->FirstParameter();
  Standard_Real cf = theCurve2d->LastParameter();

  try {  // et allez donc
    OCC_CATCH_SIGNALS
    Geom2dAPI_ProjectPointOnCurve PPOC(thePoint2d, theCurve2d, cl, cf);
    // until LowerDistanceParameter works !!
    Standard_Integer nbp = PPOC.NbPoints();
    Standard_Integer ind;
    Standard_Real distMin, d1;
    if (nbp) {
      distMin = RealLast();
      for (Standard_Integer i=1 ; i<=nbp; i++) {
	gp_Pnt2d theSol1 = PPOC.Point(i); 
	d1 = theSol1.Distance(thePoint2d);
	if (d1 < distMin) {
	  distMin = d1;
	  ind = i;
	}
      }
      if (distMin < Precision::Parametric(BRepAPI::Precision(), 0.01)) {
	theParam = PPOC.Parameter(ind);
	return Standard_True;
      }
      else {
	theParam = PPOC.Parameter(ind);
#ifdef DEBUG
	cout << "Warning : parameter should be incorrect" << endl;
#endif
	return Standard_False;
      }
    }
    else
      return Standard_False;  
  }  // end try
  catch(Standard_Failure) {
    MoniTool_DB& dbl = MoniTool_DB::Cur();
    dbl.Add("EdgeProjAux::IsPointOnCurve");
    dbl.AddRaised();
    dbl.AddXY   (thePoint2d.XY());
    dbl.AddGeom (theCurve2d);
    dbl.AddGeom (theSurface);
    return Standard_False;
  }
  return Standard_False;  // on ne sait jamais si on passe par ici ...
}

//=======================================================================
//function : CheckPointOnCurve
// Purpose : If the point2d is not lying on the pcurve, update point2d 
//           Include IsPointOnCurve Call
//           Not yet implemented : Closed Non Periodic Surfaces ->
//           Take care about crossing the seam
//=======================================================================

Standard_Boolean ShapeFix_EdgeProjAux::CheckPointOnCurve (gp_Pnt2d& thePoint2d,
							 const Handle(Geom2d_Curve)& theCurve2d,
							 const Handle(Geom_Surface)& theSurface,
							 Standard_Real& theParam) 
{
  Standard_Real myUVPrecision =  
    Precision::Parametric(BRepAPI::Precision(), 0.01);
  
  Standard_Real cf = theCurve2d->FirstParameter();
  Standard_Real cl = theCurve2d->LastParameter();

  Standard_Real iniU = thePoint2d.X();
  Standard_Real iniV = thePoint2d.Y();

  Standard_Boolean ok;

  // Non Closed Surface
  
  if (!theSurface->IsUClosed() &&
      !theSurface->IsVClosed()) {
    ShapeFix_EdgeProjAux aC2dAux;
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    return ok;
  }
  
  // UPeriodic Surface
  
  if (theSurface->IsUPeriodic()) {
    
    Standard_Real UPeriod = theSurface->UPeriod();
    Standard_Real TolProjU = UPeriod / 10;
    // Project the point2d as founded by FindUV
    
    ShapeFix_EdgeProjAux aC2dAux;
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;
    
    // Translate thePoint2d - UPeriod
    
    thePoint2d.SetX(iniU - UPeriod);
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;

    // Translate thePoint2d + UPeriod
    
    thePoint2d.SetX(iniU + UPeriod);
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;
  }
  
  if (theSurface->IsVPeriodic()) {
    
    // Reset initial U Coordinate of poind2d
    
    thePoint2d.SetX(iniU);
    
    // Project the point2d as founded by FindUV
    
    Standard_Real VPeriod = theSurface->VPeriod();
    Standard_Real TolProjV = VPeriod/10;
    ShapeFix_EdgeProjAux aC2dAux;

    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;
    
    // Translate thePoint2d - VPeriod
    
    thePoint2d.SetY(iniV - VPeriod);
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;
    
    // Translate thePoint2d + VPeriod
    
    thePoint2d.SetY(iniV + VPeriod);
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;
  }
  
  if (theSurface->IsUPeriodic() &&
      theSurface->IsVPeriodic()) {

    // Reset initial U V Coordinates of poind2d
    
    thePoint2d.SetX(iniU);
    thePoint2d.SetY(iniV);
    
    Standard_Real UPeriod = theSurface->UPeriod();
    Standard_Real TolProjU = UPeriod / 10;
    Standard_Real VPeriod = theSurface->VPeriod();
    Standard_Real TolProjV = VPeriod / 10;
    
    // Translate thePoint2d +UPeriod+VPeriod
    thePoint2d.SetX(iniU + UPeriod);
    thePoint2d.SetY(iniV + VPeriod);
    ShapeFix_EdgeProjAux aC2dAux;
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;

    // Translate thePoint2d +UPeriod-VPeriod
    thePoint2d.SetX(iniU + UPeriod);
    thePoint2d.SetY(iniV - VPeriod);
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;

    // Translate thePoint2d -UPeriod+VPeriod
    thePoint2d.SetX(iniU - UPeriod);
    thePoint2d.SetY(iniV + VPeriod);
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;

    // Translate thePoint2d -UPeriod-VPeriod
    thePoint2d.SetX(iniU - UPeriod);
    thePoint2d.SetY(iniV - VPeriod);
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;
  }

  // Case of Closed Surface : the closure tolerance is too hight;
  // Shall test is with the file 3D tolerance !

  Standard_Real uf,ul,vf,vl;
  theSurface->Bounds(uf,ul,vf,vl);
  Standard_Real ULength = ul - uf;

  if (theSurface->IsUClosed()) {
    ShapeFix_EdgeProjAux aC2dAux;
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;
    if (Abs(thePoint2d.X() - ul) < BRepAPI::Precision())
      thePoint2d.SetX(uf);
    else
      thePoint2d.SetX(ul);
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;
    else { // Partial solution for CATIA sphere and cone
#ifdef DEBUG
      cout << "Warning : uncertain trimming" << endl;
#endif
      return Standard_True;
    }
  }

  if (theSurface->IsVClosed()) {
    
    thePoint2d.SetX(iniU);
    ShapeFix_EdgeProjAux aC2dAux;

    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;
    if (Abs(thePoint2d.Y() - vl) < BRepAPI::Precision())
      thePoint2d.SetY(vf);
    else
      thePoint2d.SetY(vl);
    ok = aC2dAux.IsPointOnCurve(thePoint2d, theCurve2d, theSurface, theParam);
    if (ok)
      return Standard_True;
  }

  if (theSurface->IsUClosed() &&
      theSurface->IsVClosed()) {

    thePoint2d.SetX(iniU);
    thePoint2d.SetY(iniV);
#ifdef DEBUG
    cout << "UClosed and VClosed not yet implemented" << endl;
#endif
  }

  return Standard_False;
}

*/
