// Created on: 1994-10-25
// Created by: Laurent BOURESCHE
// Copyright (c) 1994-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

// modif : jlr branchement F(t) pour Edge/Face
//  Modified by skv - Wed Jun  9 17:16:26 2004 OCC5898
//  modified by Edward AGAPOV (eap) Fri Feb  8 2002 (bug occ67 == BUC61052)
//  ComputeData(), case where BRepBlend_Walking::Continu() can't get up to Target

#include <Adaptor2d_Curve2d.hxx>
#include <Blend_CurvPointFuncInv.hxx>
#include <Blend_RstRstFunction.hxx>
#include <Blend_SurfCurvFuncInv.hxx>
#include <Blend_SurfPointFuncInv.hxx>
#include <Blend_SurfRstFunction.hxx>
#include <BRepBlend_AppFunc.hxx>
#include <BRepBlend_AppFuncRst.hxx>
#include <BRepBlend_AppFuncRstRst.hxx>
#include <BRepBlend_AppSurf.hxx>
#include <BRepBlend_AppSurface.hxx>
#include <BRepBlend_ConstRad.hxx>
#include <BRepBlend_ConstRadInv.hxx>
#include <BRepBlend_CSWalking.hxx>
#include <BRepBlend_Line.hxx>
#include <BRepBlend_RstRstLineBuilder.hxx>
#include <BRepBlend_SurfRstLineBuilder.hxx>
#include <BRepBlend_Walking.hxx>
#include <BRepTopAdaptor_HVertex.hxx>
#include <BRepTopAdaptor_TopolTool.hxx>
#include <BSplCLib.hxx>
#include <ChFi3d_Builder.hxx>
#include <ChFi3d_Builder_0.hxx>
#include <ChFiDS_CommonPoint.hxx>
#include <ChFiDS_FaceInterference.hxx>
#include <ChFiDS_ElSpine.hxx>
#include <ChFiDS_Spine.hxx>
#include <ChFiDS_SurfData.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom2d_Line.hxx>
#include <Geom2d_TrimmedCurve.hxx>
#include <Geom2dAPI_ProjectPointOnCurve.hxx>
#include <Geom2dInt_GInter.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Surface.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GeomLib.hxx>
#include <gp_Dir2d.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Vec.hxx>
#include <gp_Vec2d.hxx>
#include <IntRes2d_IntersectionPoint.hxx>
#include <math_Vector.hxx>
#include <Precision.hxx>
#include <TopExp.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopOpeBRepBuild_HBuilder.hxx>
#include <TopOpeBRepDS_Curve.hxx>
#include <TopOpeBRepDS_DataStructure.hxx>
#include <TopOpeBRepDS_HDataStructure.hxx>
#include <TopOpeBRepDS_Surface.hxx>
#include <TopTools_ListOfShape.hxx>

#include <stdio.h>

//#define DRAW 

#ifdef DRAW 
#include <Draw_Appli.hxx>
#include <Draw_Segment2D.hxx>
#include <Draw_Marker2D.hxx>
#include <Draw_Segment3D.hxx>
#include <Draw_Marker3D.hxx>
#include <Draw.hxx>
#include <DrawTrSurf.hxx>
#include <BRepAdaptor_Surface.hxx>
static Standard_Integer IndexOfConge = 0;
#endif

#ifdef OCCT_DEBUG
extern Standard_Boolean ChFi3d_GettraceDRAWFIL(); 
extern Standard_Boolean ChFi3d_GettraceDRAWWALK(); 
extern Standard_Boolean ChFi3d_GetcontextNOOPT();
extern void ChFi3d_SettraceDRAWFIL(const Standard_Boolean b); 
extern void ChFi3d_SettraceDRAWWALK(const Standard_Boolean b); 
extern void ChFi3d_SetcontextNOOPT(const Standard_Boolean b);
#endif

#ifdef DRAW 
static void drawline(const Handle(BRepBlend_Line)& lin,
		     const Standard_Boolean iscs)
{
  Handle(Draw_Marker3D) p3d;
  Handle(Draw_Marker2D) p2d;
  Handle(Draw_Segment3D) tg3d;
  Handle(Draw_Segment2D) tg2d;
  
  for(Standard_Integer i = 1; i <= lin->NbPoints(); i++){
    const Blend_Point& pt = lin->Point(i);
    gp_Pnt point = pt.PointOnS1();
    gp_Pnt extr = point.Translated(pt.TangentOnS1());
    p3d = new Draw_Marker3D(point,Draw_Square,Draw_rouge);
    dout<<p3d;
    tg3d = new Draw_Segment3D(point,extr,Draw_rouge);
    dout<<tg3d;
    point = pt.PointOnS2();
    extr = point.Translated(pt.TangentOnS2());
    p3d = new Draw_Marker3D(point,Draw_Plus,Draw_jaune);
    dout<<p3d;
    tg3d = new Draw_Segment3D(point,extr,Draw_jaune);
    dout<<tg3d;

    Standard_Real u,v;
    pt.ParametersOnS1(u,v);
    gp_Pnt2d point2d(u,v);
    gp_Pnt2d extr2d = point2d.Translated(pt.Tangent2dOnS1());
    p2d = new Draw_Marker2D(point2d,Draw_Square,Draw_rouge);
    dout<<p2d;
    tg2d = new Draw_Segment2D(point2d,extr2d,Draw_rouge);
    dout<<tg2d;
    pt.ParametersOnS2(u,v);
    point2d.SetCoord(u,v);
    extr2d = point2d.Translated(pt.Tangent2dOnS2());
    p2d = new Draw_Marker2D(point2d,Draw_Plus,Draw_jaune);
    dout<<p2d;
    tg2d = new Draw_Segment2D(point2d,extr2d,Draw_jaune);
    dout<<tg2d;
    dout.Flush();
  }
}
#endif
//=======================================================================
//function : SearchIndex
//purpose  : 
//           
//=======================================================================
static Standard_Integer SearchIndex(const Standard_Real Value,
				    Handle(BRepBlend_Line)& Lin)
{
  Standard_Integer NbPnt =  Lin->NbPoints(), Ind;

  for (Ind = 1;  
       (Ind < NbPnt) && (Lin->Point(Ind).Parameter() < Value); )
    Ind++;
  return Ind;
}


//=======================================================================
//function : IsObst
//purpose  : 
//           
//=======================================================================
static Standard_Integer nbedconnex(const TopTools_ListOfShape& L)
{
  Standard_Integer nb = 0, i = 0;
  TopTools_ListIteratorOfListOfShape It1(L);
  for(;It1.More();It1.Next(),i++){
    const TopoDS_Shape& curs = It1.Value();
    Standard_Boolean dejavu = 0;
    TopTools_ListIteratorOfListOfShape It2(L);
    for(Standard_Integer j = 0; j < i && It2.More(); j++, It2.Next()){
      if(curs.IsSame(It2.Value())){
	dejavu = 1;
	break;
      }
    }
    if(!dejavu) nb++;
  }
  return nb;
}

static Standard_Boolean IsVois(const TopoDS_Edge&     E,
			       const TopoDS_Vertex&   Vref,
			       const ChFiDS_Map&      VEMap,
			       TopTools_MapOfShape&   DONE,
			       const Standard_Integer prof,
			       const Standard_Integer profmax)
{
  if(prof > profmax) return Standard_False;
  if(DONE.Contains(E)) return Standard_False;
  TopoDS_Vertex V1,V2;
  TopExp::Vertices(E,V1,V2);
  if(Vref.IsSame(V1) || Vref.IsSame(V2)) return Standard_True;
  DONE.Add(E);
  const TopTools_ListOfShape& L1 = VEMap(V1);
  Standard_Integer i1 = nbedconnex(L1);
  TopTools_ListIteratorOfListOfShape It1(L1);
  for(;It1.More();It1.Next()){
    const TopoDS_Edge& curE = TopoDS::Edge(It1.Value());
    if(i1 <= 2){
      if(IsVois(curE,Vref,VEMap,DONE,prof,profmax)) return Standard_True;
    }
    else if(IsVois(curE,Vref,VEMap,DONE,prof+1,profmax)) return Standard_True;
  }
  const TopTools_ListOfShape& L2 = VEMap(V2);
#ifdef OCCT_DEBUG
//  Standard_Integer i2 = nbedconnex(L2);
#endif
  TopTools_ListIteratorOfListOfShape It2(L2);
  for(;It2.More();It2.Next()){
    const TopoDS_Edge& curE = TopoDS::Edge(It2.Value());
    if(i1 <= 2){
      if(IsVois(curE,Vref,VEMap,DONE,prof,profmax)) return Standard_True;
    }
    else if(IsVois(curE,Vref,VEMap,DONE,prof+1,profmax)) return Standard_True;
  }
  return Standard_False;
}

static Standard_Boolean IsObst(const ChFiDS_CommonPoint& CP,
			       const TopoDS_Vertex&      Vref,
			       const ChFiDS_Map&         VEMap)
{
  if(!CP.IsOnArc()) return Standard_False;
  const TopoDS_Edge& E = CP.Arc();
  TopTools_MapOfShape DONE;
  Standard_Integer prof = 4;
  return !IsVois(E,Vref,VEMap,DONE,0,prof);
}

//=======================================================================
//function : CompParam
//purpose  : 
//           
//=======================================================================

static void CompParam(Geom2dAdaptor_Curve  Carc,
		      Handle(Geom2d_Curve) Ctg,
		      Standard_Real&       parc,
		      Standard_Real&       ptg,
		      const Standard_Real  prefarc,
		      const Standard_Real  preftg)
{
  Standard_Boolean found = 0;
  //(1) It is checked if the provided parameters are good 
  //    if pcurves have the same parameters as the spine.
  gp_Pnt2d point = Carc.Value(prefarc);
  Standard_Real distini = point.Distance(Ctg->Value(preftg));
  if (distini <= Precision::PConfusion()) {
    parc =  prefarc;
    ptg = preftg;
    found = Standard_True;
  }
  else {
    //(2) Intersection
#ifdef OCCT_DEBUG
    std::cout<< "CompParam : bad intersection parameters"<<std::endl; 
#endif
    IntRes2d_IntersectionPoint int2d;
    Geom2dInt_GInter Intersection;
    Standard_Integer nbpt,nbseg;
    Intersection.Perform(Geom2dAdaptor_Curve(Ctg),Carc,
			 Precision::PIntersection(),
			 Precision::PIntersection());

    Standard_Real dist = Precision::Infinite(), p1, p2;
    if (Intersection.IsDone()){
      if (!Intersection.IsEmpty()){
	nbseg = Intersection.NbSegments();
	if ( nbseg > 0 ){ 
#ifdef OCCT_DEBUG
	  std::cout<< "segments of intersection on the restrictions"<<std::endl; 
#endif  
	}
	nbpt = Intersection.NbPoints();
	for (Standard_Integer i = 1; i <= nbpt; i++) {
	  int2d = Intersection.Point(i);
	  p1 = int2d.ParamOnFirst();
	  p2 = int2d.ParamOnSecond();
	  if(Abs(prefarc - p2) < dist){
	    ptg  = p1;
	    parc = p2;
	    dist = Abs(prefarc - p2);
	    found = 1;
	  }
	}
      }
    }
  }
  
  if(!found){
    // (3) Projection...
#ifdef OCCT_DEBUG
    std::cout<<"CompParam : failed intersection PC, projection is created."<<std::endl;
#endif
    parc = prefarc;
    Geom2dAPI_ProjectPointOnCurve projector(point,Ctg);

    if(projector.NbPoints() == 0){
      // This happens in some cases when there is a vertex 
      // at the end of spine...
      ptg = preftg; 
#ifdef OCCT_DEBUG
      std::cout<<"CompParam : failed proj p2d/c2d, the extremity is taken!" <<std::endl;
#endif
    }
    else  {
      // It is checked if everything was calculated correctly (EDC402 C2)
      if  (projector.LowerDistance() < distini) 
	ptg = projector.LowerDistanceParameter();
      else  ptg = preftg;
    }
  }
}

//=======================================================================
//function : CompBlendPoint
//purpose  : create BlendPoint corresponding to a tangency on Vertex
// pmn : 15/10/1997 : returns false, if there is no pcurve    
//=======================================================================

static Standard_Boolean CompBlendPoint(const TopoDS_Vertex& V,
				       const TopoDS_Edge& E,
				       const Standard_Real W,
				       const TopoDS_Face F1,
				       const TopoDS_Face F2,
				       Blend_Point& BP)
{    
  gp_Pnt2d P1, P2;
  gp_Pnt P3d;
  Standard_Real param, f, l;
  Handle(Geom2d_Curve) pc;
  
  P3d = BRep_Tool::Pnt(V);
  param = BRep_Tool::Parameter(V,E,F1);
  pc = BRep_Tool::CurveOnSurface(E,F1,f,l);
  if (pc.IsNull()) return Standard_False;
  P1 =  pc->Value(param); 
  param = BRep_Tool::Parameter(V,E,F2);
  pc = BRep_Tool::CurveOnSurface(E,F2,f,l);
  if (pc.IsNull()) return Standard_False;
  P2 =  pc->Value(param);
  BP.SetValue(P3d, P3d, W, P1.X(), P1.Y(),  P2.X(), P2.Y());
  return  Standard_True;
}

//=======================================================================
//function :  UpdateLine
//purpose  : Updates extremities after a partial invalidation   
//=======================================================================

static void UpdateLine(Handle(BRepBlend_Line)& Line, 
		       const Standard_Boolean isfirst)
{
  Standard_Real tguide, U, V;
  if (isfirst) {
   const Blend_Point& BP = Line->Point(1);
   tguide = BP.Parameter();
   if (Line->StartPointOnFirst().ParameterOnGuide() < tguide) {
     BRepBlend_Extremity BE;
     BP.ParametersOnS1(U, V);
     BE.SetValue(BP.PointOnS1(), U, V, Precision::Confusion());
     Line->SetStartPoints(BE, Line->StartPointOnSecond());
   }
   if (Line->StartPointOnSecond().ParameterOnGuide() < tguide) {
     BRepBlend_Extremity BE;
     BP.ParametersOnS2(U, V);
     BE.SetValue(BP.PointOnS2(), U, V, Precision::Confusion());
     Line->SetStartPoints(Line->StartPointOnFirst(), BE);
   }
 }
  else {
   const Blend_Point& BP = Line->Point(Line->NbPoints());
   tguide = BP.Parameter();
   if (Line->EndPointOnFirst().ParameterOnGuide() > tguide) {
     BRepBlend_Extremity BE;
     BP.ParametersOnS1(U, V);
     BE.SetValue(BP.PointOnS1(), U, V, Precision::Confusion());
     Line->SetEndPoints(BE, Line->EndPointOnSecond());
   }
   if (Line->EndPointOnSecond().ParameterOnGuide() > tguide) {
     BRepBlend_Extremity BE;
     BP.ParametersOnS2(U, V);
     BE.SetValue(BP.PointOnS2(), U, V, Precision::Confusion());
     Line->SetEndPoints(Line->EndPointOnFirst(), BE);
   }
  }
}

//=======================================================================
//function : CompleteData
//purpose  : Calculates curves and CommonPoints from the data
//           calculated by filling.
//=======================================================================

Standard_Boolean ChFi3d_Builder::CompleteData
(Handle(ChFiDS_SurfData)&        Data,
 const Handle(Geom_Surface)&     Surfcoin,
 const Handle(Adaptor3d_Surface)& S1,
 const Handle(Geom2d_Curve)&     PC1,
 const Handle(Adaptor3d_Surface)& S2,
 const Handle(Geom2d_Curve)&     PC2,
 const TopAbs_Orientation        Or,
 const Standard_Boolean          On1,
 const Standard_Boolean          Gd1,
 const Standard_Boolean          Gd2,
 const Standard_Boolean          Gf1,
 const Standard_Boolean          Gf2)
{
  TopOpeBRepDS_DataStructure& DStr = myDS->ChangeDS();
  Data->ChangeSurf(DStr.AddSurface(TopOpeBRepDS_Surface(Surfcoin,tolesp)));
#ifdef DRAW
  ChFi3d_SettraceDRAWFIL(Standard_True);
  if (ChFi3d_GettraceDRAWFIL()) {
    IndexOfConge++;
//    char name[100];
    char* name = new char[100];
    sprintf(name,"%s_%d","Surf",IndexOfConge);
    DrawTrSurf::Set(name,Surfcoin);
  }
#endif
    
  Standard_Real UFirst,ULast,VFirst,VLast;
  Surfcoin->Bounds(UFirst,ULast,VFirst,VLast);
  if(!Gd1) Data->ChangeVertexFirstOnS1().SetPoint(Surfcoin->Value(UFirst,VFirst));
  if(!Gd2) Data->ChangeVertexFirstOnS2().SetPoint(Surfcoin->Value(UFirst,VLast));
  if(!Gf1) Data->ChangeVertexLastOnS1().SetPoint(Surfcoin->Value(ULast,VFirst));
  if(!Gf2) Data->ChangeVertexLastOnS2().SetPoint(Surfcoin->Value(ULast,VLast));

  //calculate curves side S1
  Handle(Geom_Curve) Crv3d1;
  if(!PC1.IsNull()) Crv3d1= Surfcoin->VIso(VFirst);
  gp_Pnt2d pd1(UFirst,VFirst), pf1(ULast,VFirst);
  gp_Lin2d lfil1(pd1,gp_Dir2d(gp_Vec2d(pd1,pf1)));
  Handle(Geom2d_Curve) PCurveOnSurf = new Geom2d_Line(lfil1);
  TopAbs_Orientation tra1 = TopAbs_FORWARD, orsurf = Or;
  Standard_Real x,y,w = 0.5*(UFirst+ULast);
  gp_Pnt p;
  gp_Vec du,dv;
  Handle(Geom2d_Curve) c2dtrim;
  Standard_Real tolreached = 1.e-5;
  if(!PC1.IsNull()){
    Handle(GeomAdaptor_Curve) hcS1 = new GeomAdaptor_Curve(Crv3d1);
    c2dtrim = new Geom2d_TrimmedCurve(PC1,UFirst,ULast);
    ChFi3d_SameParameter(hcS1,c2dtrim,S1,tolapp3d,tolreached);
    c2dtrim->Value(w).Coord(x,y);
    S1->D1(x,y,p,du,dv);
    gp_Vec nf = du.Crossed(dv);
    Surfcoin->D1(w,VFirst,p,du,dv);
    gp_Vec ns = du.Crossed(dv);
    if(nf.Dot(ns) > 0.)  tra1 = TopAbs_REVERSED;
    else if(On1) orsurf = TopAbs::Reverse(orsurf);
  }
  Standard_Integer Index1OfCurve = 
    DStr.AddCurve(TopOpeBRepDS_Curve(Crv3d1,tolreached));
  ChFiDS_FaceInterference& Fint1 = Data->ChangeInterferenceOnS1();
  Fint1.SetFirstParameter(UFirst);
  Fint1.SetLastParameter(ULast);
  Fint1.SetInterference(Index1OfCurve,tra1,c2dtrim,PCurveOnSurf);
  //calculate curves side S2
  Handle(Geom_Curve) Crv3d2;
  if(!PC2.IsNull()) Crv3d2 = Surfcoin->VIso(VLast);
  gp_Pnt2d pd2(UFirst,VLast), pf2(ULast,VLast);
  gp_Lin2d lfil2(pd2,gp_Dir2d(gp_Vec2d(pd2,pf2)));
  PCurveOnSurf = new Geom2d_Line(lfil2);
  TopAbs_Orientation tra2 = TopAbs_FORWARD;
  if(!PC2.IsNull()){
    Handle(GeomAdaptor_Curve) hcS2 = new GeomAdaptor_Curve(Crv3d2);
    c2dtrim = new Geom2d_TrimmedCurve(PC2,UFirst,ULast);
    ChFi3d_SameParameter(hcS2,c2dtrim,S2,tolapp3d,tolreached);
    c2dtrim->Value(w).Coord(x,y);
    S2->D1(x,y,p,du,dv);
    gp_Vec np = du.Crossed(dv);
    Surfcoin->D1(w,VLast,p,du,dv);
    gp_Vec ns = du.Crossed(dv);
    if(np.Dot(ns) < 0.) {
      tra2 = TopAbs_REVERSED;
      if(!On1) orsurf = TopAbs::Reverse(orsurf);
    }
  }
  Standard_Integer Index2OfCurve = 
    DStr.AddCurve(TopOpeBRepDS_Curve(Crv3d2,tolreached));
  ChFiDS_FaceInterference& Fint2 = Data->ChangeInterferenceOnS2();
  Fint2.SetFirstParameter(UFirst);
  Fint2.SetLastParameter(ULast);
  Fint2.SetInterference(Index2OfCurve,tra2,c2dtrim,PCurveOnSurf);
  Data->ChangeOrientation() = orsurf;
  return Standard_True;
}

//=======================================================================
//function : CompleteData
//purpose  : Calculates the surface of curves and eventually 
//           CommonPoints from the data calculated in ComputeData.
//
//  11/08/1996 : Use of F(t)
//
//=======================================================================

Standard_Boolean ChFi3d_Builder::CompleteData
(Handle(ChFiDS_SurfData)& Data,
 Blend_Function& Func,
 Handle(BRepBlend_Line)& lin,
 const Handle(Adaptor3d_Surface)& S1,
 const Handle(Adaptor3d_Surface)& S2,
 const TopAbs_Orientation Or1,
 const Standard_Boolean Gd1,
 const Standard_Boolean Gd2,
 const Standard_Boolean Gf1,
 const Standard_Boolean Gf2,
 const Standard_Boolean Reversed)
{
  Handle(BRepBlend_AppFunc) TheFunc 
    = new (BRepBlend_AppFunc)(lin, Func, tolapp3d, 1.e-5);

  Standard_Integer Degmax = 20, Segmax = 5000;
  BRepBlend_AppSurface approx (TheFunc, 
			       lin->Point(1).Parameter(),
			       lin->Point(lin->NbPoints()).Parameter(),
			       tolapp3d, 1.e-5, //tolapp2d, tolerance max
			       tolappangle, // Contact G1 
			       myConti, Degmax, Segmax);  
  if (!approx.IsDone()) {
#ifdef OCCT_DEBUG
    std::cout << "Approximation non faite !!!" << std::endl;
#endif
    return Standard_False;
  }
#ifdef OCCT_DEBUG
  approx.Dump(std::cout);
#endif
  return StoreData( Data, approx, lin, S1, S2, Or1, Gd1, Gd2, Gf1, Gf2, Reversed);
} 


//=======================================================================
//function : CompleteData
//purpose  : New overload for functions surf/rst
// jlr le 28/07/97 branchement F(t)
//=======================================================================

Standard_Boolean ChFi3d_Builder::CompleteData
(Handle(ChFiDS_SurfData)&        Data,
 Blend_SurfRstFunction&          Func,
 Handle(BRepBlend_Line)&         lin,
 const Handle(Adaptor3d_Surface)& S1,
 const Handle(Adaptor3d_Surface)& S2,
 const TopAbs_Orientation        Or,
 const Standard_Boolean          Reversed)
{
  Handle(BRepBlend_AppFuncRst) TheFunc 
    = new (BRepBlend_AppFuncRst)(lin, Func, tolapp3d, 1.e-5);
  BRepBlend_AppSurface approx (TheFunc, 
			       lin->Point(1).Parameter(),
			       lin->Point(lin->NbPoints()).Parameter(),
			       tolapp3d, 1.e-5, //tolapp2d, tolerance max
			       tolappangle, // Contact G1 
			       myConti);  
 if (!approx.IsDone()) {
#ifdef OCCT_DEBUG
    std::cout << "Approximation is not done!" << std::endl;
#endif  
    return Standard_False;
  }
#ifdef OCCT_DEBUG
  approx.Dump(std::cout);
#endif

  return StoreData(Data,approx,lin,S1,S2,Or,0,0,0,0,Reversed);
} 



//=======================================================================
//function : CompleteData
//purpose  : New overload for functions rst/rst
// jlr le 28/07/97 branchement F(t)
//=======================================================================

Standard_Boolean ChFi3d_Builder::CompleteData
(Handle(ChFiDS_SurfData)&        Data,
 Blend_RstRstFunction&           Func,
 Handle(BRepBlend_Line)&         lin,
 const Handle(Adaptor3d_Surface)& S1,
 const Handle(Adaptor3d_Surface)& S2,
 const TopAbs_Orientation        Or)
{
  Handle(BRepBlend_AppFuncRstRst) TheFunc 
    = new (BRepBlend_AppFuncRstRst)(lin, Func, tolapp3d, 1.e-5);
  BRepBlend_AppSurface approx (TheFunc, 
			       lin->Point(1).Parameter(),
			       lin->Point(lin->NbPoints()).Parameter(),
			       tolapp3d, 1.e-5, //tolapp2d, tolerance max
			       tolappangle, // Contact G1 
			       myConti);  
 if (!approx.IsDone()) {
#ifdef OCCT_DEBUG
    std::cout << "Approximation non faite !!!" << std::endl;
#endif  
    return Standard_False;
  }
#ifdef OCCT_DEBUG
  approx.Dump(std::cout);
#endif

  return StoreData(Data,approx,lin,S1,S2,Or,0,0,0,0);
} 




//=======================================================================
//function : StoreData
//purpose  : Copy of an approximation result in SurfData.
//=======================================================================

Standard_Boolean ChFi3d_Builder::StoreData(Handle(ChFiDS_SurfData)& Data,
					   const AppBlend_Approx& approx,
					   const Handle(BRepBlend_Line)& lin,
					   const Handle(Adaptor3d_Surface)& S1,
					   const Handle(Adaptor3d_Surface)& S2,
					   const TopAbs_Orientation Or1,
					   const Standard_Boolean Gd1,
					   const Standard_Boolean Gd2,
					   const Standard_Boolean Gf1,
					   const Standard_Boolean Gf2,
					   const Standard_Boolean Reversed)
{
  // Small control tools.
  static Handle(GeomAdaptor_Curve) checkcurve;
  if(checkcurve.IsNull()) checkcurve = new GeomAdaptor_Curve();
  GeomAdaptor_Curve& chc = *checkcurve;
  Standard_Real tolget3d, tolget2d, tolaux, tolC1,  tolcheck;
  Standard_Real  tolC2 = 0.;
  approx.TolReached(tolget3d, tolget2d);
  tolaux = approx.TolCurveOnSurf(1);
  tolC1 = tolget3d + tolaux;
  if(!S2.IsNull()) {
    tolaux = approx.TolCurveOnSurf(2);
    tolC2 = tolget3d + tolaux;
  }

  TopOpeBRepDS_DataStructure& DStr = myDS->ChangeDS();
  // By default parametric space is created using a square surface
  // to be able to parameterize in U by # R*teta // a revoir lbo 29/08/97
  const TColStd_Array1OfReal& ku = approx.SurfUKnots();
  const TColStd_Array1OfReal& kv = approx.SurfVKnots();
  Standard_Real larg = (kv(kv.Upper())-kv(kv.Lower()));
  TColStd_Array1OfReal& kku = *((TColStd_Array1OfReal*)((void*)&ku));
  BSplCLib::Reparametrize(0.,larg,kku);
  Handle(Geom_BSplineSurface) Surf = 
    new Geom_BSplineSurface(approx.SurfPoles(),approx.SurfWeights(),
			    kku,kv,
			    approx.SurfUMults(),approx.SurfVMults(),
			    approx.UDegree(),approx.VDegree());
// extension of the surface 

  Standard_Real length1,length2;
  length1=Data->FirstExtensionValue();
  length2=Data->LastExtensionValue();

  Handle(Geom_BoundedSurface) aBndSurf = Surf;
  Standard_Boolean ext1 = Standard_False, ext2 = Standard_False;
  Standard_Real eps = Max(tolget3d, 2. * Precision::Confusion());
  if (length1 > eps)
  {
    gp_Pnt P11, P21;
    P11 = Surf->Pole(1, 1);
    P21 = Surf->Pole(Surf->NbUPoles(), 1);
    if (P11.Distance(P21) > eps)
    {
      //to avoid extending surface with singular boundary
      GeomLib::ExtendSurfByLength(aBndSurf, length1, 1, Standard_False, Standard_False);
      ext1 = Standard_True;
    }
  }
  if (length2 > eps)
  {
    gp_Pnt P12, P22;
    P12 = Surf->Pole(1, Surf->NbVPoles());
    P22 = Surf->Pole(Surf->NbUPoles(), Surf->NbVPoles());
    if (P12.Distance(P22) > eps)
    {
      //to avoid extending surface with singular boundary
      GeomLib::ExtendSurfByLength(aBndSurf, length2, 1, Standard_False, Standard_True);
      ext2 = Standard_True;
    }
  }
  Surf = Handle(Geom_BSplineSurface)::DownCast(aBndSurf);

  //Correction of surface on extremities
  if (!ext1)
  {
    gp_Pnt P11, P21;
    P11 = lin->StartPointOnFirst().Value();
    P21 = lin->StartPointOnSecond().Value();
    Surf->SetPole(1, 1, P11);
    Surf->SetPole(Surf->NbUPoles(), 1, P21);
  }
  if (!ext2)
  {
    gp_Pnt P12, P22;
    P12 = lin->EndPointOnFirst().Value();
    P22 = lin->EndPointOnSecond().Value();
    Surf->SetPole(1, Surf->NbVPoles(), P12);
    Surf->SetPole(Surf->NbUPoles(), Surf->NbVPoles(), P22);
  }

  Data->ChangeSurf(DStr.AddSurface(TopOpeBRepDS_Surface(Surf,tolget3d)));

#ifdef DRAW
  ChFi3d_SettraceDRAWFIL(Standard_True);
  if (ChFi3d_GettraceDRAWFIL()) {
    IndexOfConge++;
//    char name[100];
    char* name=new char[100];
    sprintf(name,"%s_%d","Surf",IndexOfConge);
    DrawTrSurf::Set(name,Surf);
  }
#endif
  Standard_Real UFirst,ULast,VFirst,VLast,pppdeb,pppfin;
  Surf->Bounds(UFirst,ULast,VFirst,VLast);
  BRepAdaptor_Curve2d brc;
  BRepAdaptor_Curve CArc;
  Handle(BRepAdaptor_Surface) 
    BS1 = Handle(BRepAdaptor_Surface)::DownCast(S1);
  Handle(BRepAdaptor_Surface) 
    BS2 = Handle(BRepAdaptor_Surface)::DownCast(S2);
  Geom2dAPI_ProjectPointOnCurve projector;

  Standard_Real Uon1 = UFirst, Uon2 = ULast;
  Standard_Integer ion1 = 1, ion2 = 2;
  if(Reversed) { Uon1 = ULast; Uon2 = UFirst; ion1 = 2; ion2 = 1; }
  
  // The SurfData is filled in what concerns S1,
  Handle(Geom_Curve) Crv3d1 = Surf->UIso(Uon1);
  gp_Pnt2d pori1(Uon1,0.);
  gp_Lin2d lfil1(pori1,gp::DY2d());
  Handle(Geom2d_Curve) PCurveOnSurf = new Geom2d_Line(lfil1);
  Handle(Geom2d_Curve) PCurveOnFace;
  PCurveOnFace = new 
    Geom2d_BSplineCurve(approx.Curve2dPoles(ion1),approx.Curves2dKnots(),
			approx.Curves2dMults(),approx.Curves2dDegree());
  
  
   Standard_Real par1=PCurveOnFace->FirstParameter();
   Standard_Real par2= PCurveOnFace->LastParameter();
   chc.Load(Crv3d1,par1,par2);
   
 if(!ChFi3d_CheckSameParameter(checkcurve,PCurveOnFace,S1,tolC1,tolcheck)){
#ifdef OCCT_DEBUG
   std::cout<<"approximate tolerance under-valued : "<<tolC1<<" for "<<tolcheck<<std::endl;
#endif 
    tolC1 = tolcheck;
  }
  Standard_Integer Index1OfCurve = 
    DStr.AddCurve(TopOpeBRepDS_Curve(Crv3d1,tolC1));
  
  Standard_Real uarc,utg;
  if(Gd1){
    TopoDS_Face forwfac = BS1->Face();
    forwfac.Orientation(TopAbs_FORWARD);
    brc.Initialize(Data->VertexFirstOnS1().Arc(),forwfac);
    ChFiDS_CommonPoint& V = Data->ChangeVertexFirstOnS1();
    CArc.Initialize(V.Arc());
    CompParam(brc,PCurveOnFace,uarc,utg, V.ParameterOnArc(), V.Parameter());
    tolcheck = CArc.Value(uarc).Distance(V.Point());
    V.SetArc(tolC1+tolcheck,V.Arc(),uarc,V.TransitionOnArc());
    pppdeb = utg;
  }
  else pppdeb = VFirst;
  if(Gf1){
    TopoDS_Face forwfac = BS1->Face();
    forwfac.Orientation(TopAbs_FORWARD);
    ChFiDS_CommonPoint& V = Data->ChangeVertexLastOnS1();
    brc.Initialize(V.Arc(),forwfac);
    CArc.Initialize(V.Arc());
    CompParam(brc,PCurveOnFace,uarc,utg, V.ParameterOnArc(), V.Parameter());
    tolcheck = CArc.Value(uarc).Distance(V.Point());
    V.SetArc(tolC1+tolcheck,V.Arc(),uarc,V.TransitionOnArc());
    pppfin = utg;
  }
  else pppfin = VLast;
  ChFiDS_FaceInterference& Fint1 = Data->ChangeInterferenceOnS1();
  Fint1.SetFirstParameter(pppdeb);
  Fint1.SetLastParameter(pppfin);
  TopAbs_Orientation TraOn1;
  if(Reversed) TraOn1 = ChFi3d_TrsfTrans(lin->TransitionOnS2());
  else TraOn1 = ChFi3d_TrsfTrans(lin->TransitionOnS1());
  Fint1.SetInterference(Index1OfCurve,TraOn1,PCurveOnFace,PCurveOnSurf);
  
  // SurfData is filled in what concerns S2,
  Handle(Geom_Curve) Crv3d2 = Surf->UIso(Uon2);
  gp_Pnt2d pori2(Uon2,0.);
  gp_Lin2d lfil2(pori2,gp::DY2d());
  PCurveOnSurf = new Geom2d_Line(lfil2);
  if(!S2.IsNull()){
    PCurveOnFace = new Geom2d_BSplineCurve(approx.Curve2dPoles(ion2),
					   approx.Curves2dKnots(),
					   approx.Curves2dMults(),
					   approx.Curves2dDegree());
    chc.Load(Crv3d2,par1,par2);
   if(!ChFi3d_CheckSameParameter(checkcurve,PCurveOnFace,S2,tolC2,tolcheck)){
#ifdef OCCT_DEBUG
      std::cout<<"approximate tolerance under-evaluated : "<<tolC2<<" for "<<tolcheck<<std::endl;
#endif 
      tolC2 = tolcheck;
    }
  }
  Standard_Integer Index2OfCurve = 
    DStr.AddCurve(TopOpeBRepDS_Curve(Crv3d2,tolC2));
  if(Gd2){
    TopoDS_Face forwfac = BS2->Face();
    forwfac.Orientation(TopAbs_FORWARD);
    brc.Initialize(Data->VertexFirstOnS2().Arc(),forwfac);
    ChFiDS_CommonPoint& V = Data->ChangeVertexFirstOnS2();
    CArc.Initialize(V.Arc());
    CompParam(brc,PCurveOnFace,uarc,utg, V.ParameterOnArc(), V.Parameter());
    tolcheck = CArc.Value(uarc).Distance(V.Point());
    V.SetArc(tolC2+tolcheck,V.Arc(),uarc,V.TransitionOnArc());
    pppdeb = utg;
  }
  else pppdeb = VFirst;
  if(Gf2){
    TopoDS_Face forwfac = BS2->Face();
    forwfac.Orientation(TopAbs_FORWARD);
    brc.Initialize(Data->VertexLastOnS2().Arc(),forwfac);
    ChFiDS_CommonPoint& V = Data->ChangeVertexLastOnS2();
    CArc.Initialize(V.Arc());
    CompParam(brc,PCurveOnFace,uarc,utg, V.ParameterOnArc(), V.Parameter());
    tolcheck = CArc.Value(uarc).Distance(V.Point());
    V.SetArc(tolC2+tolcheck,V.Arc(),uarc,V.TransitionOnArc());
    pppfin = utg;
  }
  else pppfin = VLast;
  ChFiDS_FaceInterference& Fint2 = Data->ChangeInterferenceOnS2();
  Fint2.SetFirstParameter(pppdeb);
  Fint2.SetLastParameter(pppfin);
  if(!S2.IsNull()){
    TopAbs_Orientation TraOn2;
    if(Reversed) TraOn2 = ChFi3d_TrsfTrans(lin->TransitionOnS1());
    else TraOn2 = ChFi3d_TrsfTrans(lin->TransitionOnS2());
    Fint2.SetInterference(Index2OfCurve,TraOn2,PCurveOnFace,PCurveOnSurf);
  }
  else {
    Handle(Geom2d_Curve) bidpc;
    Fint2.SetInterference
      (Index2OfCurve,TopAbs_FORWARD,bidpc,PCurveOnSurf);
  }

  // the orientation of the fillet in relation to the faces is evaluated,

  Handle(Adaptor3d_Surface) Sref = S1;
  PCurveOnFace = Fint1.PCurveOnFace();
  if(Reversed){ Sref = S2; PCurveOnFace = Fint2.PCurveOnFace(); }
  
//  Modified by skv - Wed Jun  9 17:16:26 2004 OCC5898 Begin
//   gp_Pnt2d PUV = PCurveOnFace->Value((VFirst+VLast)/2.);
//   gp_Pnt P;
//   gp_Vec Du1,Du2,Dv1,Dv2;
//   Sref->D1(PUV.X(),PUV.Y(),P,Du1,Dv1);
//   Du1.Cross(Dv1);
//   if (Or1 == TopAbs_REVERSED) Du1.Reverse();
//   Surf->D1(UFirst,(VFirst+VLast)/2.,P,Du2,Dv2);
//   Du2.Cross(Dv2);
//   if (Du1.Dot(Du2)>0) Data->ChangeOrientation() = TopAbs_FORWARD;
//   else Data->ChangeOrientation() = TopAbs_REVERSED;

  Standard_Real    aDelta = VLast - VFirst;
  Standard_Integer aDenom = 2;

  for(;;) {
    Standard_Real aDeltav = aDelta/aDenom;
    Standard_Real aParam  = VFirst + aDeltav;
    gp_Pnt2d      PUV     = PCurveOnFace->Value(aParam);
    gp_Pnt        P;
    gp_Vec        Du1,Du2,Dv1,Dv2;

    Sref->D1(PUV.X(),PUV.Y(),P,Du1,Dv1);
    Du1.Cross(Dv1);

    if (Or1 == TopAbs_REVERSED)
      Du1.Reverse();

    Surf->D1(UFirst, aParam, P, Du2, Dv2);
    Du2.Cross(Dv2);

    if (Du1.Magnitude() <= tolget3d ||
	Du2.Magnitude() <= tolget3d) {
      aDenom++;

      if (Abs(aDeltav) <= tolget2d)
	return Standard_False;

      continue;
    }

    if (Du1.Dot(Du2)>0)
      Data->ChangeOrientation() = TopAbs_FORWARD;
    else
      Data->ChangeOrientation() = TopAbs_REVERSED;

    break;
  }
//  Modified by skv - Wed Jun  9 17:16:26 2004 OCC5898 End
  
  if(!Gd1 && !S1.IsNull())
    ChFi3d_FilCommonPoint(lin->StartPointOnFirst(),lin->TransitionOnS1(),
			  Standard_True, Data->ChangeVertex(1,ion1),tolC1);
  if(!Gf1 && !S1.IsNull())
    ChFi3d_FilCommonPoint(lin->EndPointOnFirst(),lin->TransitionOnS1(),
			  Standard_False,Data->ChangeVertex(0,ion1),tolC1);
  if(!Gd2 && !S2.IsNull())
    ChFi3d_FilCommonPoint(lin->StartPointOnSecond(),lin->TransitionOnS2(),
			  Standard_True, Data->ChangeVertex(1,ion2),tolC2);
  if(!Gf2 && !S2.IsNull())
    ChFi3d_FilCommonPoint(lin->EndPointOnSecond(),lin->TransitionOnS2(),
			  Standard_False, Data->ChangeVertex(0,ion2),tolC2);
  // Parameters on ElSpine
  Standard_Integer nbp = lin->NbPoints();
  Data->FirstSpineParam(lin->Point(1).Parameter());
  Data->LastSpineParam(lin->Point(nbp).Parameter());
  return Standard_True;
}			 



//=======================================================================
//function : ComputeData
//purpose  : Head of the path edge/face for the bypass of obstacle.
//=======================================================================

Standard_Boolean ChFi3d_Builder::ComputeData
(Handle(ChFiDS_SurfData)&         Data,
 const Handle(ChFiDS_ElSpine)&   HGuide,
 Handle(BRepBlend_Line)&          Lin,
 const Handle(Adaptor3d_Surface)&  S1,
 const Handle(Adaptor3d_TopolTool)& I1,
 const Handle(Adaptor3d_Surface)&  S2,
 const Handle(Adaptor2d_Curve2d)&  PC2,
 const Handle(Adaptor3d_TopolTool)& I2,
 Standard_Boolean&                Decroch,
 Blend_SurfRstFunction&           Func,
 Blend_FuncInv&                   FInv,
 Blend_SurfPointFuncInv&          FInvP,
 Blend_SurfCurvFuncInv&           FInvC,
 const Standard_Real              PFirst,
 const Standard_Real              MaxStep,
 const Standard_Real              Fleche,
 const Standard_Real              TolGuide,
 Standard_Real&                   First,
 Standard_Real&                   Last,
 const math_Vector&               Soldep,
 const Standard_Boolean           Inside,
 const Standard_Boolean           Appro,
 const Standard_Boolean           Forward,
 const Standard_Boolean           RecP,
 const Standard_Boolean           RecS,
 const Standard_Boolean           RecRst)
{
  BRepBlend_SurfRstLineBuilder TheWalk(S1,I1,S2,PC2,I2);
  
  Data->FirstExtensionValue(0);
  Data->LastExtensionValue(0); 

  Standard_Boolean reverse = (!Forward || Inside);
  Standard_Real SpFirst = HGuide->FirstParameter();
  Standard_Real SpLast =  HGuide->LastParameter();
  Standard_Real Target = SpLast;
  if(reverse) Target = SpFirst;
  Standard_Real Targetsov = Target;
  
  Standard_Real MS = MaxStep;
  Standard_Integer again = 0;
  Standard_Integer nbptmin = 3; //jlr
  Standard_Integer Nbpnt = 1;
  // the initial solution is reframed if necessary.
  math_Vector ParSol(1,3);
  Standard_Real NewFirst = PFirst;
  if(RecP || RecS || RecRst){
    if(!TheWalk.PerformFirstSection(Func,FInv,FInvP,FInvC,PFirst,Target,Soldep,
				    tolesp,TolGuide,RecRst,RecP,RecS,
				    NewFirst,ParSol)){
#ifdef OCCT_DEBUG
      std::cout<<"ChFi3d_Builder::ComputeData : calculation fail first section"<<std::endl;
#endif
      return Standard_False;
    }
  }
  else {
    ParSol = Soldep;
  }

  while (again < 2){
    TheWalk.Perform (Func,FInv,FInvP,FInvC,NewFirst,Last,
		     MS,TolGuide,ParSol,tolesp,Fleche,Appro);

    if (!TheWalk.IsDone()) {
#ifdef OCCT_DEBUG
      std::cout << "Path not created" << std::endl;
#endif  
      return Standard_False;
    }
  
    if (reverse) {
      if (!TheWalk.Complete(Func,FInv,FInvP,FInvC,SpLast)) {
#ifdef OCCT_DEBUG
	std::cout << "Not completed" << std::endl;
#endif
      }
    }  
  

    Lin = TheWalk.Line();
    Nbpnt = Lin->NbPoints();
    if (Nbpnt <= 1 && again == 0)  {
      again++;
#ifdef OCCT_DEBUG
      std::cout <<"one point of the path MS/50 is attempted."<<std::endl;
#endif  
      MS = MS/50.; Target = Targetsov;
    }
    else if (Nbpnt<=nbptmin && again == 0)  {
      again++;
#ifdef OCCT_DEBUG
      std::cout <<"Number of points is too small, the step is reduced"<<std::endl;
#endif  
      Standard_Real u1 = Lin->Point(1).Parameter();
      Standard_Real u2 = Lin->Point(Nbpnt).Parameter();
      MS = (u2-u1)/(nbptmin+1.0);
//      std::cout << " MS : " << MS << " u1 : " << u1 << " u2 : " << u2 << " nbptmin : " << nbptmin << std::endl;
      Target = Targetsov;
    }
    else if(Nbpnt<=nbptmin){
#ifdef OCCT_DEBUG
      std::cout <<"Number of points is still too small, quit"<<std::endl;
#endif  
      return Standard_False;
    }
    else {
      again = 2;
    }
  }
#ifdef DRAW
  ChFi3d_SettraceDRAWWALK(Standard_True);
  if(ChFi3d_GettraceDRAWWALK()) drawline(Lin,Standard_True);
#endif  
  if(Forward) Decroch = TheWalk.DecrochEnd();
  else Decroch = TheWalk.DecrochStart();
  Last = Lin->Point(Nbpnt).Parameter();
  First = Lin->Point(1).Parameter();
  return Standard_True;
}


//=======================================================================
//function : ComputeData
//purpose  : Heading of the path edge/edge for the bypass of obstacle.
//=======================================================================

Standard_Boolean ChFi3d_Builder::ComputeData
(Handle(ChFiDS_SurfData)&         Data,
 const Handle(ChFiDS_ElSpine)&   HGuide,
 Handle(BRepBlend_Line)&          Lin,
 const Handle(Adaptor3d_Surface)&  S1,
 const Handle(Adaptor2d_Curve2d)&  PC1,
 const Handle(Adaptor3d_TopolTool)& I1,
 Standard_Boolean&                Decroch1,
 const Handle(Adaptor3d_Surface)&  S2,
 const Handle(Adaptor2d_Curve2d)&  PC2,
 const Handle(Adaptor3d_TopolTool)& I2,
 Standard_Boolean&                Decroch2,
 Blend_RstRstFunction&            Func,
 Blend_SurfCurvFuncInv&           FInv1,
 Blend_CurvPointFuncInv&          FInvP1,
 Blend_SurfCurvFuncInv&           FInv2,
 Blend_CurvPointFuncInv&          FInvP2,
 const Standard_Real              PFirst,
 const Standard_Real              MaxStep,
 const Standard_Real              Fleche,
 const Standard_Real              TolGuide,
 Standard_Real&                   First,
 Standard_Real&                   Last,
 const math_Vector&               Soldep,
 const Standard_Boolean           Inside,
 const Standard_Boolean           Appro,
 const Standard_Boolean           Forward,
 const Standard_Boolean           RecP1,
 const Standard_Boolean           RecRst1,
 const Standard_Boolean           RecP2,
 const Standard_Boolean           RecRst2)
{
  BRepBlend_RstRstLineBuilder TheWalk(S1, PC1, I1, S2, PC2, I2);
  
  Data->FirstExtensionValue(0);
  Data->LastExtensionValue(0); 

  Standard_Boolean reverse = (!Forward || Inside);
  Standard_Real SpFirst = HGuide->FirstParameter();
  Standard_Real SpLast =  HGuide->LastParameter();
  Standard_Real Target = SpLast;
  if(reverse) Target = SpFirst;
  Standard_Real Targetsov = Target;
  
  Standard_Real MS = MaxStep;
  Standard_Integer again = 0;
  Standard_Integer nbptmin = 3; //jlr
  Standard_Integer Nbpnt = 0;
  // the initial solution is reframed if necessary.
  math_Vector ParSol(1,2);
  Standard_Real NewFirst = PFirst;
  if (RecP1 || RecRst1 || RecP2 || RecRst2) {
    if (!TheWalk.PerformFirstSection(Func, FInv1, FInvP1, FInv2, FInvP2, PFirst, Target, Soldep,
	  			     tolesp, TolGuide, RecRst1, RecP1, RecRst2, RecP2,
				     NewFirst, ParSol)){
#ifdef OCCT_DEBUG
      std::cout<<"ChFi3d_Builder::ComputeData : fail calculation first section"<<std::endl;
#endif
      return Standard_False;
    }
  }
  else {
    ParSol = Soldep;
  }

  while (again < 2){
    TheWalk.Perform (Func, FInv1, FInvP1, FInv2, FInvP2, NewFirst, Last,
		     MS, TolGuide, ParSol, tolesp, Fleche, Appro);

    if (!TheWalk.IsDone()) {
#ifdef OCCT_DEBUG
      std::cout << "Path not done" << std::endl;
#endif  
      return Standard_False;
    }
  
    if (reverse) {
      if (!TheWalk.Complete(Func, FInv1, FInvP1, FInv2, FInvP2, SpLast)) {
#ifdef OCCT_DEBUG
	std::cout << "Not completed" << std::endl;
#endif
      }
    }  
  

    Lin = TheWalk.Line();
    Nbpnt = Lin->NbPoints();
    if (Nbpnt <= 1 && again == 0)  {
      again++;
#ifdef OCCT_DEBUG
      std::cout <<"one point of path MS/50 is attempted."<<std::endl;
#endif  
      MS = MS/50.; Target = Targetsov;
    }
    else if (Nbpnt<=nbptmin && again == 0)  {
      again++;
#ifdef OCCT_DEBUG
      std::cout <<"Number of points is too small, the step is reduced"<<std::endl;
#endif  
      Standard_Real u1 = Lin->Point(1).Parameter();
      Standard_Real u2 = Lin->Point(Nbpnt).Parameter();
      MS = (u2-u1)/(nbptmin+1);
      Target = Targetsov;
    }
    else if(Nbpnt<=nbptmin){
#ifdef OCCT_DEBUG
      std::cout <<"Number of points is still too small, quit"<<std::endl;
#endif  
      return Standard_False;
    }
    else {
      again = 2;
    }
  }
#ifdef DRAW
  ChFi3d_SettraceDRAWWALK(Standard_True);
  if(ChFi3d_GettraceDRAWWALK()) drawline(Lin,Standard_True);
#endif  
  if (Forward) {
    Decroch1 = TheWalk.Decroch1End();
    Decroch2 = TheWalk.Decroch2End();
  }
  else {
    Decroch1 = TheWalk.Decroch1Start();
    Decroch2 = TheWalk.Decroch2Start();  
  }
  Last  = Lin->Point(Nbpnt).Parameter();
  First = Lin->Point(1).Parameter();
  return Standard_True;
}


//=======================================================================
//function : SimulData
//purpose  : Heading of the path edge/face for the bypass of obstacle in simulation mode.
//=======================================================================

Standard_Boolean ChFi3d_Builder::SimulData
(Handle(ChFiDS_SurfData)&         /*Data*/,
 const Handle(ChFiDS_ElSpine)&   HGuide,
 Handle(BRepBlend_Line)&          Lin,
 const Handle(Adaptor3d_Surface)&  S1,
 const Handle(Adaptor3d_TopolTool)& I1,
 const Handle(Adaptor3d_Surface)&  S2,
 const Handle(Adaptor2d_Curve2d)&  PC2,
 const Handle(Adaptor3d_TopolTool)& I2,
 Standard_Boolean&                Decroch,
 Blend_SurfRstFunction&           Func,
 Blend_FuncInv&                   FInv,
 Blend_SurfPointFuncInv&          FInvP,
 Blend_SurfCurvFuncInv&           FInvC,
 const Standard_Real              PFirst,
 const Standard_Real              MaxStep,
 const Standard_Real              Fleche,
 const Standard_Real              TolGuide,
 Standard_Real&                   First,
 Standard_Real&                   Last,
 const math_Vector&               Soldep,
 const Standard_Integer           NbSecMin,
 const Standard_Boolean           Inside,
 const Standard_Boolean           Appro,
 const Standard_Boolean           Forward,
 const Standard_Boolean           RecP,
 const Standard_Boolean           RecS,
 const Standard_Boolean           RecRst)
{
  BRepBlend_SurfRstLineBuilder TheWalk(S1,I1,S2,PC2,I2);

  Standard_Boolean reverse = (!Forward || Inside);
  Standard_Real SpFirst = HGuide->FirstParameter();
  Standard_Real SpLast =  HGuide->LastParameter();
  Standard_Real Target = SpLast;
  if(reverse) Target = SpFirst;
  Standard_Real Targetsov = Target;
  
  Standard_Real MS = MaxStep;
  Standard_Integer again = 0;
  Standard_Integer Nbpnt = 0; 
  // the starting solution is reframed if needed.
  math_Vector ParSol(1,3);
  Standard_Real NewFirst = PFirst;
  if(RecP || RecS || RecRst){
    if(!TheWalk.PerformFirstSection(Func,FInv,FInvP,FInvC,PFirst,Target,Soldep,
				    tolesp,TolGuide,RecRst,RecP,RecS,
				    NewFirst,ParSol)){
#ifdef OCCT_DEBUG

      std::cout<<"ChFi3d_Builder::SimulData : fail calculate first section"<<std::endl;
#endif
      return Standard_False;
    }
  }
  else {
    ParSol = Soldep;
  }

  while (again < 2){
    TheWalk.Perform (Func,FInv,FInvP,FInvC,NewFirst,Last,
		     MS,TolGuide,ParSol,tolesp,Fleche,Appro);
    if (!TheWalk.IsDone()) {
#ifdef OCCT_DEBUG
      std::cout << "Path not done" << std::endl;
#endif
      return Standard_False;
    }
    if (reverse) {
      if (!TheWalk.Complete(Func,FInv,FInvP,FInvC,SpLast)) {
#ifdef OCCT_DEBUG
	std::cout << "Not completed" << std::endl;
#endif
      }
    }  
    Lin = TheWalk.Line();
    Nbpnt = Lin->NbPoints();
    if (Nbpnt <= 1 && again == 0)  {
      again++;
#ifdef OCCT_DEBUG
      std::cout <<"one point of path MS/50 is attempted."<<std::endl;
#endif
      MS = MS/50.; Target = Targetsov;
    }
    else if (Nbpnt <= NbSecMin && again == 0)  {
      again++;
#ifdef OCCT_DEBUG
      std::cout <<"Number of points is too small, the step is reduced"<<std::endl;
#endif
      Standard_Real u1 = Lin->Point(1).Parameter();
      Standard_Real u2 = Lin->Point(Nbpnt).Parameter();
      MS = (u2-u1)/(NbSecMin+1);
      Target = Targetsov;
    }
    else if(Nbpnt<=NbSecMin){
#ifdef OCCT_DEBUG
      std::cout <<"Number of points is still too small, quit"<<std::endl;
#endif
      return Standard_False;
    }
    else {
      again = 2;
    }
  }
#ifdef DRAW
  ChFi3d_SettraceDRAWWALK(Standard_True);
  if(ChFi3d_GettraceDRAWWALK()) drawline(Lin,Standard_True);
#endif  
  if(Forward) Decroch = TheWalk.DecrochEnd();
  else Decroch = TheWalk.DecrochStart();
  Last = Lin->Point(Nbpnt).Parameter();
  First = Lin->Point(1).Parameter();
  return Standard_True;
}


//=======================================================================
//function : SimulData
//purpose  : Heading of path edge/edge for the bypass
//           of obstacle in simulation mode.
//=======================================================================

Standard_Boolean ChFi3d_Builder::SimulData
(Handle(ChFiDS_SurfData)&         /*Data*/,
 const Handle(ChFiDS_ElSpine)&   HGuide,
 Handle(BRepBlend_Line)&          Lin,
 const Handle(Adaptor3d_Surface)&  S1,
 const Handle(Adaptor2d_Curve2d)&  PC1,
 const Handle(Adaptor3d_TopolTool)& I1,
 Standard_Boolean&                Decroch1,
 const Handle(Adaptor3d_Surface)&  S2,
 const Handle(Adaptor2d_Curve2d)&  PC2,
 const Handle(Adaptor3d_TopolTool)& I2,
 Standard_Boolean&                Decroch2,
 Blend_RstRstFunction&            Func,
 Blend_SurfCurvFuncInv&           FInv1,
 Blend_CurvPointFuncInv&          FInvP1,
 Blend_SurfCurvFuncInv&           FInv2,
 Blend_CurvPointFuncInv&          FInvP2,
 const Standard_Real              PFirst,
 const Standard_Real              MaxStep,
 const Standard_Real              Fleche,
 const Standard_Real              TolGuide,
 Standard_Real&                   First,
 Standard_Real&                   Last,
 const math_Vector&               Soldep,
 const Standard_Integer           NbSecMin,
 const Standard_Boolean           Inside,
 const Standard_Boolean           Appro,
 const Standard_Boolean           Forward,
 const Standard_Boolean           RecP1,
 const Standard_Boolean           RecRst1,
 const Standard_Boolean           RecP2,
 const Standard_Boolean           RecRst2)
{
  BRepBlend_RstRstLineBuilder TheWalk(S1, PC1, I1, S2, PC2, I2);

  Standard_Boolean reverse = (!Forward || Inside);
  Standard_Real SpFirst = HGuide->FirstParameter();
  Standard_Real SpLast =  HGuide->LastParameter();
  Standard_Real Target = SpLast;
  if(reverse) Target = SpFirst;
  Standard_Real Targetsov = Target;
  
  Standard_Real MS = MaxStep;
  Standard_Integer again = 0;
  Standard_Integer Nbpnt = 0; 
  // The initial solution is reframed if necessary.
  math_Vector ParSol(1,2);
  Standard_Real NewFirst = PFirst;
  if (RecP1 || RecRst1 || RecP2 || RecRst2) {
    if(!TheWalk.PerformFirstSection(Func, FInv1, FInvP1, FInv2, FInvP2, PFirst, Target, Soldep,
	  			    tolesp, TolGuide, RecRst1, RecP1, RecRst2, RecP2,
				    NewFirst,ParSol)){
#ifdef OCCT_DEBUG

      std::cout<<"ChFi3d_Builder::SimulData : calculation fail first section"<<std::endl;
#endif
      return Standard_False;
    }
  }
  else {
    ParSol = Soldep;
  }

  while (again < 2){
    TheWalk.Perform (Func, FInv1, FInvP1, FInv2, FInvP2, NewFirst, Last,
		     MS, TolGuide, ParSol, tolesp, Fleche, Appro);
    if (!TheWalk.IsDone()) {
#ifdef OCCT_DEBUG
      std::cout << "Path not created" << std::endl;
#endif
      return Standard_False;
    }
    if (reverse) {
      if (!TheWalk.Complete(Func, FInv1, FInvP1, FInv2, FInvP2, SpLast)) {
#ifdef OCCT_DEBUG
	std::cout << "Not completed" << std::endl;
#endif
      }
    }  
    Lin = TheWalk.Line();
    Nbpnt = Lin->NbPoints();
    if (Nbpnt <= 1 && again == 0)  {
      again++;
#ifdef OCCT_DEBUG
      std::cout <<"only one point of path MS/50 is attempted."<<std::endl;
#endif
      MS = MS/50.; Target = Targetsov;
    }
    else if (Nbpnt <= NbSecMin && again == 0)  {
      again++;
#ifdef OCCT_DEBUG
      std::cout <<"Number of points is too small, the step is reduced"<<std::endl;
#endif
      Standard_Real u1 = Lin->Point(1).Parameter();
      Standard_Real u2 = Lin->Point(Nbpnt).Parameter();
      MS = (u2-u1)/(NbSecMin+1);
      Target = Targetsov;
    }
    else if(Nbpnt<=NbSecMin){
#ifdef OCCT_DEBUG
      std::cout <<"Number of points is still too small, quit"<<std::endl;
#endif
      return Standard_False;
    }
    else {
      again = 2;
    }
  }
#ifdef DRAW
  if(ChFi3d_GettraceDRAWWALK()) drawline(Lin,Standard_True);
#endif
  if (Forward) {
    Decroch1 = TheWalk.Decroch1End();
    Decroch2 = TheWalk.Decroch2End();
  }
  else {
    Decroch1 = TheWalk.Decroch1Start();
    Decroch2 = TheWalk.Decroch2Start();  
  }  

  Last = Lin->Point(Nbpnt).Parameter();
  First = Lin->Point(1).Parameter();
  return Standard_True;
}




//=======================================================================
//function : ComputeData
//purpose  : Construction of elementary fillet by path.
//
//=======================================================================

Standard_Boolean ChFi3d_Builder::ComputeData
(Handle(ChFiDS_SurfData)& Data,
 const Handle(ChFiDS_ElSpine)& HGuide,
 const Handle(ChFiDS_Spine)& Spine,
 Handle(BRepBlend_Line)& Lin,
 const Handle(Adaptor3d_Surface)& S1,
 const Handle(Adaptor3d_TopolTool)& I1,
 const Handle(Adaptor3d_Surface)& S2,
 const Handle(Adaptor3d_TopolTool)& I2,
 Blend_Function& Func,
 Blend_FuncInv& FInv,
 const Standard_Real PFirst,
 const Standard_Real MaxStep,
 const Standard_Real Fleche,
 const Standard_Real tolguide,
 Standard_Real& First,
 Standard_Real& Last,
 const Standard_Boolean Inside,
 const Standard_Boolean Appro,
 const Standard_Boolean Forward,
 const math_Vector& Soldep,
 Standard_Integer& intf,
 Standard_Integer& intl,
 Standard_Boolean& Gd1,
 Standard_Boolean& Gd2,
 Standard_Boolean& Gf1,
 Standard_Boolean& Gf2,
 const Standard_Boolean RecOnS1,
 const Standard_Boolean RecOnS2)
{
  //Get offset guide if exists
  Handle(ChFiDS_ElSpine) OffsetHGuide;
  if (!Spine.IsNull() &&
      Spine->Mode() == ChFiDS_ConstThroatWithPenetrationChamfer)
  {
    ChFiDS_ListOfHElSpine& ll = Spine->ChangeElSpines();
    ChFiDS_ListOfHElSpine& ll_offset = Spine->ChangeOffsetElSpines();
    ChFiDS_ListIteratorOfListOfHElSpine ILES(ll), ILES_offset(ll_offset);
    for ( ; ILES.More(); ILES.Next(),ILES_offset.Next())
    {
      const Handle(ChFiDS_ElSpine)& aHElSpine = ILES.Value();
      if (aHElSpine == HGuide)
        OffsetHGuide = ILES_offset.Value();
    }
  }
  
  //The extrensions are created in case of output of two domains
  //directly and not by path ( too hasardous ).
  Data->FirstExtensionValue(0);
  Data-> LastExtensionValue(0);

  //The eventual faces are restored to test the jump of edge.
  TopoDS_Face F1, F2;
  Handle(BRepAdaptor_Surface) HS = Handle(BRepAdaptor_Surface)::DownCast(S1); 
  if(!HS.IsNull()) F1 = HS->Face();
  HS = Handle(BRepAdaptor_Surface)::DownCast(S2); 
  if(!HS.IsNull()) F2 = HS->Face();
  
  // Path framing variables
  Standard_Real TolGuide=tolguide, TolEsp = tolesp;
  Standard_Integer nbptmin = 4;

  BRepBlend_Walking TheWalk(S1,S2,I1,I2,HGuide);

  //Start of removal, 2D path controls 
  //that qui s'accomodent mal des surfaces a parametrages non homogenes
  //en u et en v are extinguished.
  TheWalk.Check2d(0);
  
  Standard_Real MS = MaxStep;
  Standard_Integer Nbpnt;
  Standard_Real SpFirst = HGuide->FirstParameter();
  Standard_Real SpLast =  HGuide->LastParameter();

  // When the start point is inside, the path goes first to the left  
  // to determine the Last for the periodicals.
  Standard_Boolean reverse = (!Forward || Inside);
  Standard_Real Target;
  if(reverse){
    Target = SpFirst;
    if(!intf) Target = Last;
  }
  else{
    Target = SpLast + Abs(SpLast);
    if(!intl) Target = Last;
  }

  // In case if the singularity is pre-determined,
  // the path is indicated.
  if (!Spine.IsNull()){
    if (Spine->IsTangencyExtremity(Standard_True)) {
      TopoDS_Vertex V = Spine->FirstVertex();
      TopoDS_Edge E = Spine->Edges(1);
      Standard_Real param =  Spine->FirstParameter();
      Blend_Point BP;
      if (CompBlendPoint(V, E, param, F1, F2, BP)) {
	math_Vector vec(1,4);
	BP.ParametersOnS1(vec(1),vec(2));
	BP.ParametersOnS2(vec(3),vec(4));
	Func.Set(param);
	if (Func.IsSolution(vec, tolesp)) {
	  TheWalk.AddSingularPoint(BP);
	}
      }
    }
    if (Spine->IsTangencyExtremity(Standard_False)) {
      TopoDS_Vertex V = Spine->LastVertex();
      TopoDS_Edge E = Spine->Edges( Spine->NbEdges()); 
      Standard_Real param =  Spine->LastParameter();
      Blend_Point BP;
      if (CompBlendPoint(V, E, param, F1, F2, BP)) {
	math_Vector vec(1,4);
	BP.ParametersOnS1(vec(1),vec(2));
	BP.ParametersOnS2(vec(3),vec(4));
	Func.Set(param);
	if (Func.IsSolution(vec, tolesp)) {
	  TheWalk.AddSingularPoint(BP);
	}
      }
    }
  }

  //The starting solution is reframed if necessary.
  //**********************************************//
  math_Vector ParSol(1,4);
  Standard_Real NewFirst = PFirst;
  if(RecOnS1 || RecOnS2){
    if(!TheWalk.PerformFirstSection(Func,FInv,PFirst,Target,Soldep,
				    tolesp,TolGuide,RecOnS1,RecOnS2,
				    NewFirst,ParSol)){
#ifdef OCCT_DEBUG
      std::cout<<"ChFi3d_Builder::ComputeData : calculation fail first section"<<std::endl;
#endif
      return Standard_False;
    }
  }
  else {
    ParSol = Soldep;
  }

  //First the valid part is calculate, without caring for the extensions.
  //******************************************************************//
  Standard_Integer again = 0;
  Standard_Boolean tchernobyl = 0;
  Standard_Real u1sov = 0., u2sov = 0.;
  TopoDS_Face bif;
  //Max step is relevant, but too great, the vector is required to detect
  //the twists.
  if( (Abs(Last-First) <= MS * 5.) &&
      (Abs(Last-First) >= 0.01*Abs(NewFirst-Target)) ){ 
    MS = Abs(Last-First)*0.2; 
  }

  while(again < 3){
    //Path. 
    if(!again && (MS < 5*TolGuide)) MS = 5*TolGuide;
    else {
      if (5*TolGuide > MS) TolGuide = MS/5;
      if (5*TolEsp > MS) TolEsp = MS/5;
    }
    TheWalk.Perform(Func,FInv,NewFirst,Target,MS,TolGuide,
		    ParSol,TolEsp,Fleche,Appro);
    if (!TheWalk.IsDone()) {
#ifdef OCCT_DEBUG
      std::cout << "Path is not created" << std::endl;
#endif
      return Standard_False;
    }
    Lin = TheWalk.Line();
    if(HGuide->IsPeriodic() && Inside) {
      SpFirst = Lin->Point(1).Parameter();
      SpLast  = SpFirst + HGuide->Period();
      HGuide->FirstParameter(SpFirst);
      HGuide->LastParameter (SpLast );
      HGuide->SetOrigin(SpFirst);
      if (!OffsetHGuide.IsNull())
      {
        OffsetHGuide->FirstParameter(SpFirst);
        OffsetHGuide->LastParameter (SpLast );
        OffsetHGuide->SetOrigin(SpFirst);
      }
    }
    Standard_Boolean complmnt = Standard_True;
    if (Inside)  complmnt = TheWalk.Complete(Func,FInv,SpLast);
    if(!complmnt){
#ifdef OCCT_DEBUG
      std::cout << "Not completed" << std::endl;
#endif
      return Standard_False;
    }
    
    //The result is controlled using two criterions :
    //- if there is enough points,
    //- if one has gone far enough.
    Nbpnt = Lin->NbPoints();
    if (Nbpnt == 0){
#ifdef OCCT_DEBUG
      std::cout <<"0 point of path, quit."<<std::endl;
#endif
      return Standard_False;
    }
    Standard_Real fpointpar = Lin->Point(1).Parameter();
    Standard_Real lpointpar = Lin->Point(Nbpnt).Parameter();
    
    Standard_Real factor =  1./(nbptmin + 1);
    Standard_Boolean okdeb = (Forward && !Inside);  
    Standard_Boolean okfin = (!Forward && !Inside);
    if(!okdeb){
      Standard_Integer narc1 = Lin->StartPointOnFirst().NbPointOnRst();
      Standard_Integer narc2 = Lin->StartPointOnSecond().NbPointOnRst();
      okdeb = (narc1 > 0 || narc2 > 0 || (fpointpar-First) < 10*TolGuide); 
    }
    if(!okfin){
      Standard_Integer narc1 = Lin->EndPointOnFirst().NbPointOnRst();
      Standard_Integer narc2 = Lin->EndPointOnSecond().NbPointOnRst();
      okfin = (narc1 > 0 || narc2 > 0 || (Last-lpointpar) < 10*TolGuide);
    }
    if(!okdeb || !okfin || Nbpnt == 1){
      //It drags, the controls are extended, it is  expected to evaluate a
      //satisfactory maximum step. If it already done, quit.
      if(tchernobyl){
#ifdef OCCT_DEBUG
	std::cout <<"If it drags without control, quit."<<std::endl;
#endif
	return Standard_False;
      }
      tchernobyl = Standard_True;
      TheWalk.Check(0);
      if (Nbpnt == 1){
#ifdef OCCT_DEBUG
	std::cout <<"only one point of path MS/100 is attempted"<<std::endl;
	std::cout <<"and the controls are extended."<<std::endl;
#endif
	MS *= 0.01;
      }
      else{
#ifdef OCCT_DEBUG
	std::cout <<"It drags, the controls are extended."<<std::endl;
#endif
	MS = (lpointpar-fpointpar)/Nbpnt; //EvalStep(Lin);
      }
    }
    else if (Nbpnt < nbptmin){
      if(again == 0){
#ifdef OCCT_DEBUG
	std::cout <<"Number of points is too small, the step is reduced"<<std::endl;
#endif
	u1sov = fpointpar;
	u2sov = lpointpar;
	MS = (lpointpar - fpointpar) * factor;
      }
      else if(again == 1){
	if(Abs(fpointpar-u1sov)>=TolGuide || 
	   Abs(lpointpar-u2sov)>=TolGuide){
#ifdef OCCT_DEBUG
	  std::cout <<"Number of points is still too small, the step is reduced"<<std::endl;
#endif  
	  MS = (lpointpar - fpointpar) * factor;
	}
	else{
#ifdef OCCT_DEBUG
	  std::cout <<"Number of points is still too small, quit"<<std::endl;
#endif  
	  return Standard_False;
	}
      }
      again++;
    }
    else {
      again = 3;
    }
  }

  if(TheWalk.TwistOnS1()){
    Data->TwistOnS1(Standard_True);
#ifdef OCCT_DEBUG
    std::cout<<"Path completed, but TWIST on S1"<<std::endl;
#endif
  }
  if(TheWalk.TwistOnS2()){
    Data->TwistOnS2(Standard_True);
#ifdef OCCT_DEBUG
    std::cout<<"Parh completed, but TWIST on S2"<<std::endl;
#endif
  }


  //Here there is a more or less presentable result 
  //however it covers a the minimum zone.
  //The extensions are targeted.
  //*****************************//

  Gd1 = Gd2 = Gf1 = Gf2 = Standard_False;
  
  Standard_Boolean unseulsuffitdeb = (intf >= 2);
  Standard_Boolean unseulsuffitfin = (intl >= 2);
  Standard_Boolean noproldeb = (intf >= 3);
  Standard_Boolean noprolfin = (intl >= 3);

  Standard_Real Rab = 0.03*(SpLast-SpFirst);

  Standard_Boolean debarc1 = 0, debarc2 = 0;
  Standard_Boolean debcas1 = 0, debcas2 = 0;
  Standard_Boolean debobst1 = 0, debobst2 = 0;

  Standard_Boolean finarc1 = 0, finarc2 = 0;
  Standard_Boolean fincas1 = 0, fincas2 = 0;
  Standard_Boolean finobst1 = 0, finobst2 = 0;

  Standard_Integer narc1, narc2;

  Standard_Boolean backwContinueFailed = Standard_False; // eap
  if(reverse && intf) {
    narc1 = Lin->StartPointOnFirst().NbPointOnRst();
    narc2 = Lin->StartPointOnSecond().NbPointOnRst();
    if(narc1 != 0) {
      ChFi3d_FilCommonPoint(Lin->StartPointOnFirst(),Lin->TransitionOnS1(),
			    Standard_True, Data->ChangeVertexFirstOnS1(),tolesp);
      debarc1 = Standard_True;
      if(!SearchFace(Spine,Data->VertexFirstOnS1(),F1,bif)){
	//It is checked if there is not an obstacle.
	debcas1 = Standard_True;
	if(!Spine.IsNull()){
	  if(Spine->IsPeriodic()){
	    debobst1 = 1;
	  }
	  else{
	    debobst1 = IsObst(Data->VertexFirstOnS1(),
			      Spine->FirstVertex(),myVEMap);
	  }
	}
      }
    }
    if(narc2 != 0){
      ChFi3d_FilCommonPoint(Lin->StartPointOnSecond(),Lin->TransitionOnS2(),
			    Standard_True, Data->ChangeVertexFirstOnS2(),tolesp);
      debarc2 = Standard_True;
      if(!SearchFace(Spine,Data->VertexFirstOnS2(),F2,bif)){
	//It is checked if it is not an obstacle.
	debcas2 = Standard_True;
	if(!Spine.IsNull()){
	  if(Spine->IsPeriodic()){
	    debobst2 = 1;
	  }
	  else{
	    debobst2 = IsObst(Data->VertexFirstOnS2(),
			      Spine->FirstVertex(),myVEMap);
	  }
	}
      }
    }
    Standard_Boolean oncontinue = !noproldeb && (narc1 != 0 || narc2 != 0);
    if(debobst1 || debobst2) oncontinue = Standard_False;
    else if(debcas1 && debcas2) oncontinue = Standard_False;
    else if((!debcas1 && debarc1) || (!debcas2 && debarc2)) oncontinue = Standard_False;

    if(oncontinue) {
      TheWalk.ClassificationOnS1(!debarc1);
      TheWalk.ClassificationOnS2(!debarc2);
      TheWalk.Check2d(Standard_True); // It should be strict (PMN)
      TheWalk.Continu(Func,FInv,Target);
      TheWalk.ClassificationOnS1(Standard_True);
      TheWalk.ClassificationOnS2(Standard_True);
      TheWalk.Check2d(Standard_False);
      narc1 = Lin->StartPointOnFirst().NbPointOnRst();
      narc2 = Lin->StartPointOnSecond().NbPointOnRst();
//  modified by eap Fri Feb  8 11:43:48 2002 ___BEGIN___
      if(!debarc1) {
	if (narc1 == 0)
	  backwContinueFailed = Lin->StartPointOnFirst().ParameterOnGuide() > Target;
	else {
	  ChFi3d_FilCommonPoint(Lin->StartPointOnFirst(),Lin->TransitionOnS1(),
				Standard_True, Data->ChangeVertexFirstOnS1(),tolesp);
	  debarc1 = Standard_True;
	  if(!SearchFace(Spine,Data->VertexFirstOnS1(),F1,bif)){
	    //It is checked if it is not an obstacle.
	    debcas1 = Standard_True;
// 	    if(!Spine.IsNull()) {
// 	      if(Spine->IsPeriodic()){
// 	        debobst1 = 1;
// 	      }
// 	      else{
// 		debobst1 = IsObst(Data->VertexFirstOnS1(),
// 				  Spine->FirstVertex(),myVEMap);
// 	      }
// 	    }
	  }
	}
      }
      if(!debarc2) {
	if (narc2 == 0)
	  backwContinueFailed = Lin->StartPointOnSecond().ParameterOnGuide() > Target;
	else {
	  ChFi3d_FilCommonPoint(Lin->StartPointOnSecond(),Lin->TransitionOnS2(),
                                Standard_True, Data->ChangeVertexFirstOnS2(),tolesp);
          debarc2 = Standard_True;
          if(!SearchFace(Spine,Data->VertexFirstOnS2(),F2,bif)){
	    //It is checked if it is not an obstacle.
            debcas2 = Standard_True;
//             if(!Spine.IsNull()){
//               if(Spine->IsPeriodic()){
//                 debobst2 = 1;
//               }
//               else{
//                 debobst2 = IsObst(Data->VertexFirstOnS2(),
//                                   Spine->FirstVertex(),myVEMap);
//               }
//             }
          }
        }
      }
      if (backwContinueFailed) {
	// if we leave backwContinueFailed as is, we will stop in this direction
	// but we are to continue if there are no more faces on the side with arc
	// check this condition
	const ChFiDS_CommonPoint& aCP
	  = debarc1 ? Data->VertexFirstOnS1() : Data->VertexFirstOnS2();
	if (aCP.IsOnArc() && bif.IsNull())
	  backwContinueFailed = Standard_False;
      }
    }
  }
  Standard_Boolean forwContinueFailed = Standard_False;
//  modified by eap Fri Feb  8 11:44:11 2002 ___END___
  if(Forward && intl) {
    Target = SpLast;
    narc1 = Lin->EndPointOnFirst().NbPointOnRst();
    narc2 = Lin->EndPointOnSecond().NbPointOnRst();
    if(narc1 != 0){
      ChFi3d_FilCommonPoint(Lin->EndPointOnFirst(),Lin->TransitionOnS1(),
			    Standard_False, Data->ChangeVertexLastOnS1(),tolesp);
      finarc1 = Standard_True;
      if(!SearchFace(Spine,Data->VertexLastOnS1(),F1,bif)){
             //It is checked if it is not an obstacle.
	fincas1 = Standard_True;
	if(!Spine.IsNull()){
	  finobst1 = IsObst(Data->VertexLastOnS1(),
			    Spine->LastVertex(),myVEMap);
	}
      }
    }
    if(narc2 != 0){
      ChFi3d_FilCommonPoint(Lin->EndPointOnSecond(),Lin->TransitionOnS2(),
			    Standard_False, Data->ChangeVertexLastOnS2(),tolesp);
      finarc2 = Standard_True;
      if(!SearchFace(Spine,Data->VertexLastOnS2(),F2,bif)){
	 //It is checked if it is not an obstacle.
	fincas2 = Standard_True;
	if(!Spine.IsNull()){
	  finobst2 = IsObst(Data->VertexLastOnS2(),
			    Spine->LastVertex(),myVEMap);
	}
      }
    }
    Standard_Boolean oncontinue = !noprolfin && (narc1 != 0 || narc2 != 0);
    if(finobst1 || finobst2) oncontinue = Standard_False;
    else if(fincas1 && fincas2) oncontinue = Standard_False;
    else if((!fincas1 && finarc1) || (!fincas2 && finarc2)) oncontinue = Standard_False;
    
    if(oncontinue){
      TheWalk.ClassificationOnS1(!finarc1);
      TheWalk.ClassificationOnS2(!finarc2);
      TheWalk.Check2d(Standard_True); // It should be strict (PMN)
      TheWalk.Continu(Func,FInv,Target);
      TheWalk.ClassificationOnS1(Standard_True);
      TheWalk.ClassificationOnS2(Standard_True);
      TheWalk.Check2d(Standard_False);
      narc1 = Lin->EndPointOnFirst().NbPointOnRst();
      narc2 = Lin->EndPointOnSecond().NbPointOnRst();
//  modified by eap Fri Feb  8 11:44:57 2002 ___BEGIN___
      if(!finarc1) {
	if (narc1 == 0) 
	  forwContinueFailed = Lin->EndPointOnFirst().ParameterOnGuide() < Target;
	else {
	  ChFi3d_FilCommonPoint(Lin->EndPointOnFirst(),Lin->TransitionOnS1(),
				Standard_False, Data->ChangeVertexLastOnS1(),tolesp);
	  finarc1 = Standard_True;
	  if(!SearchFace(Spine,Data->VertexLastOnS1(),F1,bif)){
             //It is checked if it is not an obstacle.
	    fincas1 = Standard_True;
// 	    if(!Spine.IsNull()){
// 	      finobst1 = IsObst(Data->VertexLastOnS1(),
// 				Spine->LastVertex(),myVEMap);
// 	    }
	  }
	}
      }
      if(!finarc2) {
	if (narc2 == 0)
	  forwContinueFailed = Lin->EndPointOnSecond().ParameterOnGuide() < Target;
	else {
	  ChFi3d_FilCommonPoint(Lin->EndPointOnSecond(),Lin->TransitionOnS2(),
				Standard_False, Data->ChangeVertexLastOnS2(),tolesp);
	  finarc2 = Standard_True;
	  if(!SearchFace(Spine,Data->VertexLastOnS2(),F2,bif)){
	    //On regarde si ce n'est pas un obstacle.
	    fincas2 = Standard_True;
// 	    if(!Spine.IsNull()){
// 	      finobst2 = IsObst(Data->VertexLastOnS2(),
// 				Spine->LastVertex(),myVEMap);
// 	    }
	  }
	}
      }
      if (forwContinueFailed) {
	// if we leave forwContinueFailed as is, we will stop in this direction
	// but we are to continue if there are no more faces on the side with arc
	// check this condition
	const ChFiDS_CommonPoint& aCP
	  = finarc1 ? Data->VertexLastOnS1() : Data->VertexLastOnS2();
	if (aCP.IsOnArc() && bif.IsNull())
	  forwContinueFailed = Standard_False;
      }
//  modified by eap Fri Feb  8 11:45:10 2002 ___END___
    }
  }
  Nbpnt = Lin->NbPoints();
#ifdef DRAW
  if(ChFi3d_GettraceDRAWWALK()) drawline(Lin,Standard_False);
#endif  
  First = Lin->Point(1).Parameter();
  Last  = Lin->Point(Nbpnt).Parameter();

  // ============= INVALIDATION EVENTUELLE =============
  // ------ Preparation des prolongement par plan tangent -----
  if(reverse && intf){
    Gd1 = debcas1/* && !debobst1*/; // skv(occ67)
    Gd2 = debcas2/* && !debobst2*/; // skv(occ67)
    if ((debarc1^debarc2) && !unseulsuffitdeb && (First!=SpFirst)) {
      // Case of incomplete path, of course this ends badly : 
      // the result is truncated instead of exit.
      Standard_Real sortie;
      Standard_Integer ind;
      if (debarc1)  sortie = Data->VertexFirstOnS1().Parameter();
      else  sortie = Data->VertexFirstOnS2().Parameter();
      if (sortie - First > tolesp) {
	ind = SearchIndex(sortie, Lin);
	if (Lin->Point(ind).Parameter() == sortie) ind--;
	if (ind >= 1) {
	  Lin->Remove(1, ind);
	  UpdateLine(Lin, Standard_True);
	}
	Nbpnt = Lin->NbPoints();
	First = Lin->Point(1).Parameter();
      }
    }
    else if ((intf>=5) && !debarc1 && !debarc2 && (First!=SpFirst)) {
      Standard_Real sortie = (2*First+Last)/3;
      Standard_Integer ind;
      if (sortie - First > tolesp) {
	ind = SearchIndex(sortie, Lin);
	if (Lin->Point(ind).Parameter() == sortie) ind--;
        if (Nbpnt-ind < 3) ind = Nbpnt -3;
	if (ind >= 1) {
	  Lin->Remove(1, ind);
	  UpdateLine(Lin, Standard_True);
	}
	Nbpnt = Lin->NbPoints();
	First = Lin->Point(1).Parameter();
      }
    }
    if(Gd1 && Gd2){
      Target = Min((Lin->Point(1).Parameter() - Rab),First);
      Target = Max(Target,SpFirst);
      Data->FirstExtensionValue(Abs(Lin->Point(1).Parameter()-Target));
    }
    if (intf && !unseulsuffitdeb) intf = (Gd1 && Gd2)//;
      || backwContinueFailed; // eap
    else if (intf && unseulsuffitdeb && (intf<5)) {
      intf = (Gd1 || Gd2);
      // It is checked if there is no new face.
      if (intf && 
	  ((!debcas1 && debarc1) || (!debcas2 && debarc2)) ) intf = 0;  
    }
    else if (intf < 5) intf = 0;
  }

  if(Forward && intl){
    Gf1 = fincas1/* && !finobst1*/; // skv(occ67)
    Gf2 = fincas2/* && !finobst2*/; // skv(occ67)
    if ((finarc1 ^finarc2) && !unseulsuffitfin && (Last!=SpLast)) {
      // Case of incomplete path, of course, this ends badly : 
      // the result is truncated instead of exit.
      Standard_Real sortie;
      Standard_Integer ind;
      if (finarc1)  sortie = Data->VertexLastOnS1().Parameter();
      else  sortie = Data->VertexLastOnS2().Parameter();
      if (Last - sortie > tolesp) {
	ind = SearchIndex(sortie, Lin);
        if (Lin->Point(ind).Parameter() == sortie) ind++;
	if (ind<= Nbpnt) {
	  Lin->Remove(ind, Nbpnt);
	  UpdateLine(Lin, Standard_False);
	}
	Nbpnt = Lin->NbPoints();
	Last = Lin->Point(Nbpnt).Parameter();
      }
    }
    else if ((intl>=5) && !finarc1 && !finarc2 && (Last!=SpLast) ) {
      // The same in case when the entire "Lin" is an extension
      Standard_Real sortie = (First+2*Last)/3;
      Standard_Integer ind;
      if (Last - sortie > tolesp) {
	ind = SearchIndex(sortie, Lin);
	if (Lin->Point(ind).Parameter() == sortie) ind++;
        if (ind < 3) ind = 3;
	if (ind <= Nbpnt) {
	  Lin->Remove(ind, Nbpnt);
	  UpdateLine(Lin, Standard_False);
	}
	Nbpnt = Lin->NbPoints();
	Last = Lin->Point(Nbpnt).Parameter();
      }
    }
    if(Gf1 && Gf2) {
      Target = Max((Lin->Point(Nbpnt).Parameter() + Rab),Last);
      Target = Min(Target,SpLast);
      Data->LastExtensionValue(Abs(Target-Lin->Point(Nbpnt).Parameter()));
    }    

    if (intl && !unseulsuffitfin) intl = (Gf1 && Gf2)//;
      || forwContinueFailed;  // eap
    else if (intl && unseulsuffitfin && (intl<5)) {
      intl = (Gf1 || Gf2);// It is checked if there is no new face.
      if (intl && 
	  ((!fincas1 && finarc1) || (!fincas2 && finarc2)) ) intl = 0;  
    }
    else if (intl <5) intl = 0;
  }
  return Standard_True;
}

//=======================================================================
//function : SimulData
//purpose  : 
//=======================================================================

Standard_Boolean ChFi3d_Builder::SimulData
(Handle(ChFiDS_SurfData)& /*Data*/,
 const Handle(ChFiDS_ElSpine)& HGuide,
 const Handle(ChFiDS_ElSpine)& AdditionalHGuide,
 Handle(BRepBlend_Line)& Lin,
 const Handle(Adaptor3d_Surface)& S1,
 const Handle(Adaptor3d_TopolTool)& I1,
 const Handle(Adaptor3d_Surface)& S2,
 const Handle(Adaptor3d_TopolTool)& I2,
 Blend_Function& Func,
 Blend_FuncInv& FInv,
 const Standard_Real PFirst,
 const Standard_Real MaxStep,
 const Standard_Real Fleche,
 const Standard_Real tolguide,
 Standard_Real& First,
 Standard_Real& Last,
 const Standard_Boolean Inside,
 const Standard_Boolean Appro,
 const Standard_Boolean Forward,
 const math_Vector& Soldep,
 const Standard_Integer NbSecMin,
 const Standard_Boolean RecOnS1,
 const Standard_Boolean RecOnS2)
{
  BRepBlend_Walking TheWalk(S1,S2,I1,I2,HGuide);
  TheWalk.Check2d(Standard_False);
  
  Standard_Real MS = MaxStep;
  Standard_Real TolGuide=tolguide, TolEsp = tolesp;
  Standard_Integer Nbpnt = 0;
  Standard_Real SpFirst = HGuide->FirstParameter();
  Standard_Real SpLast =  HGuide->LastParameter();
  Standard_Boolean reverse = (!Forward || Inside);
  Standard_Real Target;
  if(reverse){
    Target = SpFirst;
  }
  else{
    Target = SpLast;
  }

  Standard_Real Targetsov = Target;
  Standard_Real u1sov = 0., u2sov = 0.; 
  // on recadre la solution de depart a la demande.
  math_Vector ParSol(1,4);
  Standard_Real NewFirst = PFirst;
  if(RecOnS1 || RecOnS2){
    if(!TheWalk.PerformFirstSection(Func,FInv,PFirst,Target,Soldep,
				    tolesp,TolGuide,RecOnS1,RecOnS2,
				    NewFirst,ParSol)){
#ifdef OCCT_DEBUG
      std::cout<<"ChFi3d_Builder::SimulData : calculation fail first section"<<std::endl;
#endif
      return Standard_False;
    }
  }
  else {
    ParSol = Soldep;
  }
  Standard_Integer again = 0;
  while(again < 3){
     // When the start point is inside, the path goes first to the left  
     // to determine the Last for the periodicals.
    if(!again && (MS < 5*TolGuide)) MS = 5*TolGuide;
    else  {
      if (5*TolGuide > MS) TolGuide = MS/5;
      if (5*TolEsp > MS) TolEsp = MS/5;
    }
      
    TheWalk.Perform(Func,FInv,NewFirst,Target,MS,TolGuide,
		    ParSol,TolEsp,Fleche,Appro);
    
    if (!TheWalk.IsDone()) {
#ifdef OCCT_DEBUG
      std::cout << "Path not created" << std::endl;
#endif
      return Standard_False;
    }
    Lin = TheWalk.Line();
    if(reverse){
      if(HGuide->IsPeriodic()) {
	SpFirst = Lin->Point(1).Parameter();
	SpLast  = SpFirst + HGuide->Period();
	HGuide->FirstParameter(SpFirst);
	HGuide->LastParameter (SpLast );
        if (!AdditionalHGuide.IsNull())
        {
          AdditionalHGuide->FirstParameter(SpFirst);
          AdditionalHGuide->LastParameter (SpLast );
        }
      }
      Standard_Boolean complmnt = Standard_True;
      if (Inside)  complmnt = TheWalk.Complete(Func,FInv,SpLast);
      if(!complmnt){
#ifdef OCCT_DEBUG
	std::cout << "Not completed" << std::endl;
#endif
	return Standard_False;
      }
    }
    Nbpnt = Lin->NbPoints();
    Standard_Real factor =  1./(NbSecMin + 1);
    if (Nbpnt == 0){
#ifdef OCCT_DEBUG
      std::cout <<"0 point of path, quit."<<std::endl;
#endif
      return Standard_False;
    }
    else if (Nbpnt == 1 && again == 0)  {
      again++;
#ifdef OCCT_DEBUG
      std::cout <<"only one point of path, MS/100 is attempted."<<std::endl;
#endif
      MS *= 0.01; Target = Targetsov;
      u1sov = u2sov = Lin->Point(1).Parameter();
    }
    else if (Nbpnt< NbSecMin && again == 0)  {
      again++;
#ifdef OCCT_DEBUG
      std::cout <<"Number of points is too small, the step is reduced"<<std::endl;
#endif
      Standard_Real u1 = u1sov = Lin->Point(1).Parameter();
      Standard_Real u2 = u2sov = Lin->Point(Nbpnt).Parameter();
      MS = (u2-u1)*factor;
      Target = Targetsov;
    }
    else if (Nbpnt < NbSecMin && again == 1)  {
      Standard_Real u1 = Lin->Point(1).Parameter();
      Standard_Real u2 = Lin->Point(Nbpnt).Parameter();
      if(Abs(u1-u1sov)>=TolGuide || Abs(u2-u2sov)>=TolGuide){
	again++;
#ifdef OCCT_DEBUG
	std::cout <<"Number of points is still too small, the step is reduced"<<std::endl;
#endif
	MS /= 100;
	Target = Targetsov;
      }
      else{
#ifdef OCCT_DEBUG
	std::cout <<"Number of points is still too small, quit"<<std::endl;
#endif
	return Standard_False;
      }
    }
    else if(Nbpnt < NbSecMin){
#ifdef OCCT_DEBUG
      std::cout <<"Number of points is still too small, quit"<<std::endl;
#endif
      return Standard_False;
    }
    else {
      again = 3;
    }
  }
#ifdef DRAW
  if(ChFi3d_GettraceDRAWWALK()) drawline(Lin,Standard_False);
#endif  
  First = Lin->Point(1).Parameter();
  Last  = Lin->Point(Nbpnt).Parameter();
  return Standard_True;
}

