// File:	BRepFill_MultiLine.cxx
// Created:	Mon Nov 14 15:32:23 1994
// Author:	Bruno DUMORTIER
//		<dub@fuegox>


#include <BRepFill_MultiLine.ixx>

#include <BRepIntCurveSurface_Inter.hxx>
#include <gp.hxx>
#include <gp_Lin.hxx>
#include <gp_Ax3.hxx>
#include <gp_Lin2d.hxx>
#include <gp_Circ2d.hxx>
#include <Precision.hxx>
#include <BRep_Tool.hxx>
#include <Geom_Line.hxx>
#include <Geom_Plane.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <Geom2d_TrimmedCurve.hxx>
#include <Geom_Surface.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom2d_Line.hxx>
#include <GeomProjLib.hxx>
#include <Geom2dAPI_ProjectPointOnCurve.hxx>
#include <Geom2dInt_GInter.hxx>
#include <IntRes2d_IntersectionPoint.hxx>
#include <Standard_ConstructionError.hxx>
#include <IntRes2d_IntersectionSegment.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <ElCLib.hxx>


#include <GeomAdaptor_Surface.hxx>
#include <GeomAbs_SurfaceType.hxx>

#ifdef DRAW
#include <DrawTrSurf.hxx>
#endif

#ifdef DEB
static Standard_Boolean AffichCurve = Standard_False;
static Standard_Integer NbProj = 1;
#endif
//POP pour NT
#include <stdio.h>

//=======================================================================
//function : isIsoU
//purpose  : 
//=======================================================================

static Standard_Boolean isIsoU(const TopoDS_Face& Face,
			       const TopoDS_Edge& Edge ) 
{
  Handle(Geom2d_Curve) C;
  Handle(Geom2d_Line) Li;
  Standard_Real f,l;

  C = BRep_Tool::CurveOnSurface(Edge,Face, f, l);
  if ( C.IsNull()) {
    Standard_ConstructionError::Raise ("BRepFill_MultiLine : Edge without PCurve");
  }
  
  gp_Dir2d D = C->DN(f,1);

  if (Abs(D.Dot(gp::DX2d())) < Abs(D.Dot(gp::DY2d()))) 
    return Standard_True;
  else            
    return Standard_False;
}




//=======================================================================
//function : BRepFill_MultiLine
//purpose  : 
//=======================================================================

BRepFill_MultiLine::BRepFill_MultiLine()
{
}


//=======================================================================
//function : BRepFill_MultiLine
//purpose  : 
//=======================================================================

BRepFill_MultiLine::BRepFill_MultiLine(const TopoDS_Face&     Face1, 
				       const TopoDS_Face&     Face2,
				       const TopoDS_Edge&     Edge1,
				       const TopoDS_Edge&     Edge2,
				       const Standard_Boolean Inv1,
				       const Standard_Boolean Inv2,
				       const Handle(Geom2d_Curve)& Bissec) :
myFace1(Face1 ),
myFace2(Face2 ),
myBis  (Bissec),
myKPart(0)
{
  // eval if myedges are IsoU or not
  myIsoU1 = isIsoU(Face1, Edge1);
  myIsoU2 = isIsoU(Face2, Edge2);

  // eval myU1, myV1, myU2, myV2;
  Handle(Geom_Plane) RefPlane;
  Handle(Geom_Plane) BasisPlane = new Geom_Plane(0.,0.,1.,0.);
  TopLoc_Location L;

  TopExp_Explorer Exp;
  Standard_Real Umin,Vmin,Umax,Vmax,U,V;
  gp_Pnt2d P1,P2;
  gp_Vec DZ;
  gp_Pnt P;

  // Result on Face1
  Standard_Boolean First = Standard_True;
  for (Exp.Init(myFace1,TopAbs_EDGE);Exp.More(); Exp.Next()) {
    TopoDS_Edge CurEdge = TopoDS::Edge(Exp.Current());
    BRep_Tool::UVPoints(CurEdge,myFace1,P1,P2);
    if ( First) {
      First = Standard_False;
      Umin = Min(P1.X(),P2.X());
      Umax = Max(P1.X(),P2.X());
 
      Vmin = Min(P1.Y(),P2.Y());
      Vmax = Max(P1.Y(),P2.Y());
    }
    else {
      U    = Min(P1.X(),P2.X());
      Umin = Min(Umin,U);
      U    = Max(P1.X(),P2.X());
      Umax = Max(Umax,U);

      V    = Min(P1.Y(),P2.Y());
      Vmin = Min(Vmin,V);
      V    = Max(P1.Y(),P2.Y());
      Vmax = Max(Vmax,V);
    }
  }
  

  // recuperons les isos dans leur domaine de restriction.
  Handle(Geom_Curve) UU1, UU2, VV1, VV2;
  Handle(Geom_Surface) S;
  S = BRep_Tool::Surface(myFace1,L);  
  if (!L.IsIdentity())
    S = Handle(Geom_Surface)::DownCast(S->Transformed(L.Transformation()));

  if ( myIsoU1) {
    if (!BRep_Tool::Degenerated(Edge1) && !Inv1) {
      UU1 = S->UIso(Umin);
      GeomAdaptor_Curve Dummy(UU1);
      if (Dummy.GetType() == GeomAbs_Circle && 
	  Dummy.Circle().Radius() < Precision::Confusion()) {
	UU1 = S->UIso(Umax);
      }
    }
    else {
      UU1 = S->UIso(Umax);
      GeomAdaptor_Curve Dummy(UU1);
      if (Dummy.GetType() == GeomAbs_Circle && 
	  Dummy.Circle().Radius() < Precision::Confusion()) {
	UU1 = S->UIso(Umin);
      }
    }
    VV1 = S->VIso(Vmin);
  }
  else {
    if (!BRep_Tool::Degenerated(Edge1) && !Inv1) {
      UU1 = S->VIso(Vmin);    
      GeomAdaptor_Curve Dummy(UU1);
      if (Dummy.GetType() == GeomAbs_Circle && 
	  Dummy.Circle().Radius() < Precision::Confusion()) {
	UU1 = S->VIso(Vmax);
      }
    }
    else {
      UU1 = S->VIso(Vmax);
      GeomAdaptor_Curve Dummy(UU1);
      if (Dummy.GetType() == GeomAbs_Circle && 
	  Dummy.Circle().Radius() < Precision::Confusion()) {
	UU1 = S->VIso(Vmin);
      }
    }
    VV1 = S->UIso(Umin);
  }

  if ( myIsoU1) {
    Standard_Real dummyUmin = Umin, dummyUmax = Umax;
    Umin = Vmin; 
    Umax = Vmax;
    Vmin = dummyUmin;
    Vmax = dummyUmax;
  }

  // essai dub
  GeomAdaptor_Surface GAS1(S);
  GeomAbs_SurfaceType Type1 = GAS1.GetType();

  if ( UU1->IsPeriodic()) {
    ElCLib::AdjustPeriodic(UU1->FirstParameter(),
			   UU1->LastParameter(),
			   Precision::PConfusion(),
			   Umin, Umax);
  }
  if ( VV1->IsPeriodic()) {
    ElCLib::AdjustPeriodic(VV1->FirstParameter(),
			   VV1->LastParameter(),
			   Precision::PConfusion(),
			   Vmin, Vmax);
  }
  if (GAS1.GetType() == GeomAbs_Sphere) {
    if (myIsoU1)
      ElCLib::AdjustPeriodic(-PI/2.,PI/2.,
			     Precision::PConfusion(),
			     Umin, Umax);
    else
      ElCLib::AdjustPeriodic(-PI/2.,PI/2.,
			     Precision::PConfusion(),
			     Vmin, Vmax);
  }
  // fin essai dub

  myU1 = Geom2dAdaptor_Curve(GeomProjLib::Curve2d(UU1, BasisPlane),
			     Umin, Umax);

  UU1->D1(Umin, P, DZ);
  RefPlane = new Geom_Plane(gp_Ax3(P,DZ,gp::DZ()));

  myV1 = Geom2dAdaptor_Curve(GeomProjLib::Curve2d(VV1, RefPlane),
			     Vmin, Vmax);


  First = Standard_True;
  for (Exp.Init(myFace2,TopAbs_EDGE);Exp.More(); Exp.Next()) {
    TopoDS_Edge CurEdge = TopoDS::Edge(Exp.Current());
    BRep_Tool::UVPoints(CurEdge,myFace2,P1,P2);
    if ( First) {
      First = Standard_False;
      Umin = Min(P1.X(),P2.X());
      Umax = Max(P1.X(),P2.X());
 
      Vmin = Min(P1.Y(),P2.Y());
      Vmax = Max(P1.Y(),P2.Y());
    }
    else {
      U    = Min(P1.X(),P2.X());
      Umin = Min(Umin,U);
      U    = Max(P1.X(),P2.X());
      Umax = Max(Umax,U);

      V    = Min(P1.Y(),P2.Y());
      Vmin = Min(Vmin,V);
      V    = Max(P1.Y(),P2.Y());
      Vmax = Max(Vmax,V);
    }
  }

  // recuperons les isos dans leur domaine de restriction.
  S = BRep_Tool::Surface(myFace2,L);

  if (!L.IsIdentity())
    S = Handle(Geom_Surface)::DownCast(S->Transformed(L.Transformation()));

  if ( myIsoU2) {
    if (!BRep_Tool::Degenerated(Edge2) && !Inv2) {
      UU2 = S->UIso(Umin);    
      GeomAdaptor_Curve Dummy(UU2);
      if (Dummy.GetType() == GeomAbs_Circle && 
	  Dummy.Circle().Radius() < Precision::Confusion()) {
	UU2 = S->UIso(Umax);
      }
    }
    else {
      UU2 = S->UIso(Umax);
      GeomAdaptor_Curve Dummy(UU2);
      if (Dummy.GetType() == GeomAbs_Circle && 
	  Dummy.Circle().Radius() < Precision::Confusion()) {
	UU2 = S->UIso(Umin);
      }
    }
    VV2 = S->VIso(Vmin);
  }
  else {
    if (!BRep_Tool::Degenerated(Edge2) && !Inv2) {
      UU2 = S->VIso(Vmin);
      GeomAdaptor_Curve Dummy(UU2);
      if (Dummy.GetType() == GeomAbs_Circle && 
	  Dummy.Circle().Radius() < Precision::Confusion()) {
	UU2 = S->VIso(Vmax);
      }
    }
    else {
      UU2 = S->VIso(Vmax);
      GeomAdaptor_Curve Dummy(UU2);
      if (Dummy.GetType() == GeomAbs_Circle && 
	  Dummy.Circle().Radius() < Precision::Confusion()) {
	UU2 = S->VIso(Vmin);
      }
    }
    VV2 = S->UIso(Umin);
  }
    
  if ( myIsoU2) {
    Standard_Real dummyUmin = Umin, dummyUmax = Umax;
    Umin = Vmin; 
    Umax = Vmax;
    Vmin = dummyUmin;
    Vmax = dummyUmax;
  }

  // essai dub
  GeomAdaptor_Surface GAS2(S);
  GeomAbs_SurfaceType Type2 = GAS2.GetType();

  if ( UU2->IsPeriodic()) {
    ElCLib::AdjustPeriodic(UU2->FirstParameter(),
			   UU2->LastParameter(),
			   Precision::PConfusion(),
			   Umin, Umax);
  }
  if ( VV2->IsPeriodic()) {
    ElCLib::AdjustPeriodic(VV2->FirstParameter(),
			   VV2->LastParameter(),
			   Precision::PConfusion(),
			   Vmin, Vmax);
  }
  if (GAS2.GetType() == GeomAbs_Sphere) {
    if (myIsoU2)
      ElCLib::AdjustPeriodic(-PI/2.,PI/2.,
			     Precision::PConfusion(),
			     Umin, Umax);
    else
      ElCLib::AdjustPeriodic(-PI/2.,PI/2.,
			     Precision::PConfusion(),
			     Vmin, Vmax);
  }
  // fin essai dub

  myU2 = Geom2dAdaptor_Curve(GeomProjLib::Curve2d(UU2, BasisPlane),
			     Umin, Umax);

  UU2->D1(Umin, P, DZ);
  RefPlane = new Geom_Plane(gp_Ax3(P,DZ,gp::DZ()));
  myV2 = Geom2dAdaptor_Curve(GeomProjLib::Curve2d(VV2, RefPlane),
			     Vmin, Vmax);

  // eval if in a particular case.
  // Cas Particulier si :
  //     1) - Bissec droite
  //        - Bissec orthogonale a l`element de la base.
  //        ==> Iso sur les 2 faces.
  //     2) - Bissec droite
  //        - les 2 surfaces sont des plans.
  myCont  = GeomAbs_C0;

  if ( myBis.GetType() == GeomAbs_Line) {
    Standard_Real DeltaU = myBis.LastParameter()  - myBis.FirstParameter();
    gp_Pnt2d P1 = ValueOnF1(myBis.FirstParameter() + 0.1*DeltaU);
    gp_Pnt2d P2 = ValueOnF1(myBis.FirstParameter() + 0.9*DeltaU);
    if ( myIsoU1) {
      if ( Abs(P1.Y() - P2.Y()) < Precision::Confusion())
	myKPart = 1;
    }
    else {
      if ( Abs(P1.X() - P2.X()) < Precision::Confusion())
	myKPart = 1;
    }
    
    if ( myKPart == 1)
      myCont = GeomAbs_G1;

    if ( (Type1 == GeomAbs_Plane) && (Type2 == GeomAbs_Plane)) {
      myKPart = 2;
    }
  }
}


//=======================================================================
//function : IsParticularCase
//purpose  : 
//=======================================================================

Standard_Boolean BRepFill_MultiLine::IsParticularCase() const 
{
  return ( myKPart != 0);
}


//=======================================================================
//function : Curves
//purpose  : 
//=======================================================================

void BRepFill_MultiLine::Curves(Handle(Geom_Curve)& Curve,
				Handle(Geom2d_Curve)& PCurve1,
				Handle(Geom2d_Curve)& PCurve2) const 
{
  if ( myKPart == 1) {
    gp_Pnt2d      P1,P2,PMil;
    Standard_Real f,l;

    P1   = ValueOnF1(myBis.FirstParameter());
    P2   = ValueOnF1(myBis.LastParameter());

    // on recherche la valeur de l iso avec le point milieu 
    // les bouts pouvant etre des points degeneres.

    PMil = ValueOnF1(0.5*(myBis.FirstParameter() + myBis.LastParameter()));
    
    TopLoc_Location L;
    Handle(Geom_Surface) S = BRep_Tool::Surface(myFace1,L);
    if (!L.IsIdentity())
      S = Handle(Geom_Surface)::DownCast(S->Transformed(L.Transformation()));
    
    Standard_Boolean Sens;
    if ( !myIsoU1) {
      Curve   = S->UIso(PMil.X());
      Sens    = P1.Y() < P2.Y();
      if ( Sens) 
	Curve   = new Geom_TrimmedCurve(Curve, P1.Y(), P2.Y(), Sens);
      else
	Curve   = new Geom_TrimmedCurve(Curve, P2.Y(), P1.Y(), Sens);
      
      f = Curve->FirstParameter();
      l = Curve->LastParameter();
      if ( Sens) 
	PCurve1 = new Geom2d_Line(gp_Pnt2d(PMil.X(),P1.Y() - f), gp::DY2d());
      else
	PCurve1 = new Geom2d_Line(gp_Pnt2d(PMil.X(),P1.Y() + f),-gp::DY2d());
      PCurve1 = new Geom2d_TrimmedCurve( PCurve1 ,f ,l);
    }
    else {
      Curve   = S->VIso(PMil.Y());
      Sens = P1.X() < P2.X();
      if (Sens)
	Curve   = new Geom_TrimmedCurve(Curve, P1.X(), P2.X(), Sens);
      else
	Curve   = new Geom_TrimmedCurve(Curve, P2.X(), P1.X(), Sens);
      
      f = Curve->FirstParameter();
      l = Curve->LastParameter();
      if ( Sens) 
	PCurve1 = new Geom2d_Line(gp_Pnt2d(P1.X() - f,PMil.Y()), gp::DX2d());
      else
	PCurve1 = new Geom2d_Line(gp_Pnt2d(P1.X() + f,PMil.Y()), -gp::DX2d());
      PCurve1 = new Geom2d_TrimmedCurve( PCurve1 ,f ,l);
    }
		     
    P1   = ValueOnF2(myBis.FirstParameter());
    P2   = ValueOnF2(myBis.LastParameter());
    PMil = ValueOnF2(0.5*(myBis.FirstParameter() + myBis.LastParameter()));
		     
    if (!myIsoU2) {
      Sens = P1.Y() < P2.Y();
      if ( Sens) 
	PCurve2 = new Geom2d_Line(gp_Pnt2d(PMil.X(),(P1.Y() - f)), gp::DY2d());
      else
	PCurve2 = new Geom2d_Line(gp_Pnt2d(PMil.X(),(P1.Y() + f)), -gp::DY2d());
    }
    else {
      Sens = P1.X() < P2.X();
      if ( Sens) 
	PCurve2 = new Geom2d_Line(gp_Pnt2d(P1.X() - f ,PMil.Y()), gp::DX2d());
      else
	PCurve2 = new Geom2d_Line(gp_Pnt2d(P1.X() + f ,PMil.Y()), -gp::DX2d());
    }
    PCurve2 = new Geom2d_TrimmedCurve( PCurve2 ,f ,l);
  }
  else if ( myKPart == 2) {
    TopLoc_Location L;
    
    Handle(Geom_Surface) S = BRep_Tool::Surface(myFace1,L);
    if (!L.IsIdentity())
      S = Handle(Geom_Surface)::DownCast(S->Transformed(L.Transformation()));
    
    if (S->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) 
      S = Handle(Geom_RectangularTrimmedSurface)::DownCast(S)->BasisSurface();

    Handle(Geom_Plane) Plane = Handle(Geom_Plane)::DownCast(S);
    // eval the 3d curve corresponding to the bissectrice.
    gp_Pnt2d P = myBis.Line().Location();
    gp_Dir2d D = myBis.Line().Direction();
    Handle(Geom_Line) Line = new Geom_Line(gp_Pnt(P.X(),P.Y(),0.),
					   gp_Dir(D.X(),D.Y(),0.) );
    Handle(Geom_TrimmedCurve) TLine = 
      new Geom_TrimmedCurve(Line, myBis.FirstParameter(),
			          myBis.LastParameter());
    Curve = GeomProjLib::ProjectOnPlane(TLine, Plane, 
					gp::DZ(), Standard_False);

#ifdef DRAW
    if ( AffichCurve) {
//POP pour NT
      //      char name[100];
      char* name = new char[100];
      sprintf(name,"C2_%d",NbProj);
      DrawTrSurf::Set(name,TLine);
      sprintf(name,"C3_%d",NbProj);
      DrawTrSurf::Set(name,Curve);
      sprintf(name,"SS_%d",NbProj);
      DrawTrSurf::Set(name,Plane);
      NbProj++;
    }
#endif

    // eval PCurve1
    PCurve1 = GeomProjLib::Curve2d(Curve,Plane);
    
    // eval PCurve2
    S = BRep_Tool::Surface(myFace2,L);
    if (!L.IsIdentity())
      S = Handle(Geom_Surface)::DownCast(S->Transformed(L.Transformation()));
    if (S->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) 
      S = Handle(Geom_RectangularTrimmedSurface)::DownCast(S)->BasisSurface();
    Plane = Handle(Geom_Plane)::DownCast(S);
    PCurve2 = GeomProjLib::Curve2d(Curve,Plane);
  }
}


//=======================================================================
//function : FirstParameter
//purpose  : 
//=======================================================================

Standard_Real BRepFill_MultiLine::FirstParameter() const 
{
  return myBis.FirstParameter();
}


//=======================================================================
//function : LastParameter
//purpose  : 
//=======================================================================

Standard_Real BRepFill_MultiLine::LastParameter() const 
{
  return myBis.LastParameter();
}


//=======================================================================
//function : Value
//purpose  : 
//=======================================================================

gp_Pnt BRepFill_MultiLine::Value(const Standard_Real U) const 
{
  Handle(Geom_Surface) S;
  TopLoc_Location L;

  S = BRep_Tool::Surface(myFace1,L);  

  gp_Pnt2d P2d = ValueOnF1(U);

  gp_Pnt P3d = S->Value(P2d.X(), P2d.Y());
  P3d.Transform(L.Transformation());

  return P3d;
}


//=======================================================================
//function : ValueOnFace
//purpose  : 
//=======================================================================

static gp_Pnt2d ValueOnFace(const Standard_Real        U,
			    const Geom2dAdaptor_Curve& TheBis,
			    const Geom2dAdaptor_Curve& TheU,
			    const Geom2dAdaptor_Curve& TheV,
			    const Standard_Boolean     IsIsoU)
{
  gp_Pnt2d P = TheBis.Value(U);

  Geom2dAPI_ProjectPointOnCurve Ext(P,TheU.Curve(),
				    TheU.FirstParameter(),
				    TheU.LastParameter());
#ifdef DRAW
  if (AffichCurve) {
    char* TheUname = "TheU";
    char* PP1name = "PP1";
    DrawTrSurf::Set(TheUname,TheU.Curve());
    DrawTrSurf::Set(PP1name,P);
//    DrawTrSurf::Set("TheU",TheU.Curve());
//    DrawTrSurf::Set("PP1",P);
  }
#endif

  Standard_Real UU =0., Dist = Precision::Infinite(), D1, D2;

  if ( !Ext.NbPoints() == 0 ) {    
    UU = Ext.LowerDistanceParameter();
    Dist = Ext.LowerDistance();
  }
  // Controle avec les `bouts` 
  D1 = P.Distance(TheU.Value(TheU.FirstParameter()));
  D2 = P.Distance(TheU.Value(TheU.LastParameter()));

  if (D1 < Dist || D2 < Dist) {
    if ( Abs( D1 - D2) < Precision::Confusion()) {
      if ( TheU.GetType() == GeomAbs_Circle) {
	gp_Vec2d Axis = TheU.Circle().XAxis().Direction();
	gp_Vec2d D12d = TheBis.DN(TheBis.FirstParameter(),1);
	Standard_Real Ang = Axis.Angle(D12d);
	if ( !TheU.Circle().IsDirect()) Ang = -Ang;
	UU = ElCLib::InPeriod( Ang, TheU.FirstParameter(), 
			            TheU.FirstParameter() + 2*PI);
	Dist = TheU.Circle().Radius();
      }
      else {
#ifdef DEB
	cout << "MultiLine : D1 = D2 and the Curve is not a circle" << endl;
	cout << "  ---> ValueOnFace failed at parameter U = " << U << endl;
#endif
	Standard_ConstructionError::Raise("BRepFill_MultiLine: ValueOnFace");
      }
    }
    else if ( D1 < D2) {
      Dist = D1;
      UU   = TheU.FirstParameter();
    }
    else {
      Dist = D2;
      UU   = TheU.LastParameter();
    }
  }

  Standard_Real Tol = Precision::Confusion();
  Standard_Real VV;

  gp_Pnt2d PF = TheV.Value(TheV.FirstParameter());
  gp_Pnt2d PL = TheV.Value(TheV.LastParameter());  
  
  if (Abs(Dist - Abs(PF.Y())) < Tol) {
    VV = TheV.FirstParameter();
  }
  else if (Abs(Dist - Abs(PL.Y())) < Tol) {
    VV = TheV.LastParameter();
  }  
  else {  
    // test si la courbe est du cote `Y negatif`.
    if ( Min( PF.Y(),PL.Y()) < -Tol)  Dist = -Dist;
   
    Handle(Geom2d_Line) Line 
      = new Geom2d_Line(gp_Pnt2d(0., Dist), gp::DX2d());
    
#ifdef DRAW
    if (AffichCurve) {
      static Standard_CString aTheV = "TheV" ;
      DrawTrSurf::Set(aTheV,TheV.Curve());
      static Standard_CString aLINF1 = "LINF1" ;
      DrawTrSurf::Set(aLINF1,Line);
    }
#endif    
    
    Geom2dAdaptor_Curve Cu1 = TheV;
    Geom2dAdaptor_Curve Cu2( Line);
    
    Standard_Real TolConf = 0.;

    Geom2dInt_GInter Intersector(Cu1,Cu2,TolConf,Tol);

    if ( !Intersector.IsDone()) {
#ifdef DEB
      cout << "Intersector not done" << endl;
      cout << "  ---> ValueonFace failed at parameter U = " << U << endl;
#endif
      return gp_Pnt2d(0.,0.);
    }
    else {
      if ( Intersector.NbPoints() > 0) {
	VV = Intersector.Point(1).ParamOnFirst();
      }
      else if ( Intersector.NbSegments() > 0) {
	IntRes2d_IntersectionSegment Seg = Intersector.Segment(1);
	Standard_Real VS1 = Seg.FirstPoint().ParamOnFirst();
	Standard_Real VS2 = Seg.LastPoint().ParamOnFirst();
	gp_Pnt2d      PS1 = TheV.Value(VS1);
	gp_Pnt2d      PS2 = TheV.Value(VS2);
	Standard_Real Alp = (Dist - PS1.Y())/(PS2.Y() - PS1.Y());
	VV = Alp*(VS2 - VS1) + VS1;
      }
      else {
#ifdef DEB
	cout << "Intersector done, but no points found" << endl;
	cout << "  ---> ValueonFace failed at parameter U = " << U << endl;
#endif
	if (Abs(Dist - PL.Y()) < Abs(Dist - PF.Y()))
	  VV = TheV.LastParameter();
	else 
	  VV = TheV.FirstParameter();
      }
    }
  }

  if ( IsIsoU) 
    return gp_Pnt2d(VV,UU);
  else
    return gp_Pnt2d(UU,VV);
}

//=======================================================================
//function : ValueOnF1
//purpose  : 
//=======================================================================

gp_Pnt2d BRepFill_MultiLine::ValueOnF1(const Standard_Real U) const 
{
  return ValueOnFace(U,myBis,myU1,myV1,myIsoU1);
}


//=======================================================================
//function : ValueOnF2
//purpose  : 
//=======================================================================

gp_Pnt2d BRepFill_MultiLine::ValueOnF2(const Standard_Real U) const 
{
  return ValueOnFace(U,myBis,myU2,myV2,myIsoU2);
}

//=======================================================================
//function : Value3dOnF1OnF2
//purpose  : 
//=======================================================================

void BRepFill_MultiLine::Value3dOnF1OnF2(const Standard_Real U,
					       gp_Pnt&       P3d,
					       gp_Pnt2d&     PF1,
					       gp_Pnt2d&     PF2)
const
{
  PF1 = ValueOnFace(U,myBis,myU1,myV1,myIsoU1);
  PF2 = ValueOnFace(U,myBis,myU2,myV2,myIsoU2);

  Handle(Geom_Surface) S;
  TopLoc_Location L;

  S = BRep_Tool::Surface(myFace1,L);  
  P3d = S->Value(PF1.X(), PF1.Y());
  P3d.Transform(L.Transformation());
}

//=======================================================================
//function : Continuity
//purpose  : 
//=======================================================================

GeomAbs_Shape BRepFill_MultiLine::Continuity() const
{
  return myCont;
}
