// Created on: 1993-04-09
// Created by: Laurent BUCHARD
// Copyright (c) 1993-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.

//#ifndef OCCT_DEBUG
//#define No_Standard_RangeError
//#define No_Standard_OutOfRange
//#endif


#define  TOLTANGENCY         0.00000001
#define  TOLERANCE_ANGULAIRE 1.e-12//0.00000001
#define  TOLERANCE           0.00000001

#define NBSAMPLESONCIRCLE  32
#define NBSAMPLESONELLIPSE 32
#define NBSAMPLESONPARAB   16
#define NBSAMPLESONHYPR    32

#include <ElSLib.hxx>
#include <Intf_SectionPoint.hxx>
#include <Intf_TangentZone.hxx>
#include <Intf_Tool.hxx>
#include <math_FunctionSetRoot.hxx>
#include <IntCurveSurface_IntersectionPoint.hxx>
#include <IntCurveSurface_IntersectionSegment.hxx>
#include <IntAna_IntConicQuad.hxx>
#include <IntAna_Quadric.hxx>
#include <gp_Vec.hxx>
#include <gp_Dir.hxx>
#include <Precision.hxx>
#include <IntAna_IntLinTorus.hxx>

#include <GeomAbs_Shape.hxx>
#include <GeomAbs_CurveType.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pln.hxx>
#include <gp_Lin.hxx>
#include <GProp_PEquation.hxx>
#include <GProp_PGProps.hxx>
#include <GProp_PrincipalProps.hxx>
#include <Extrema_ExtElC.hxx>
#include <Extrema_POnCurv.hxx>



#include <ProjLib_Plane.hxx>
#include <IntAna2d_AnaIntersection.hxx>
#include <gp_Lin2d.hxx>
#include <IntAna2d_IntPoint.hxx>
#include <gp_Parab2d.hxx>
#include <IntAna2d_Conic.hxx>
#include <IntAna2d_AnaIntersection.hxx>
#include <gp_Hypr2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>


#include <TColgp_Array2OfPnt.hxx>
#include <TColStd_HArray1OfReal.hxx>
#include <Adaptor3d_TopolTool.hxx>
#include <ElCLib.hxx>
//#define ICS_DEB
static 
  void EstLimForInfExtr(const gp_Lin&   Line,
			const TheSurface& surface, 
			const Standard_Boolean IsOffSurf,
			const Standard_Integer nbsu, 
			const Standard_Boolean U1inf, 
			const Standard_Boolean U2inf, 
			const Standard_Boolean V1inf, 
			const Standard_Boolean V2inf, 
			Standard_Real& U1new, 
			Standard_Real& U2new, 
			Standard_Real& V1new, 
			Standard_Real& V2new, 
			Standard_Boolean& NoIntersection);

static 
  void EstLimForInfRevl(const gp_Lin&   Line,
			const TheSurface& surface, 
			const Standard_Boolean U1inf, 
			const Standard_Boolean U2inf, 
			const Standard_Boolean V1inf, 
			const Standard_Boolean V2inf, 
			Standard_Real& U1new, 
			Standard_Real& U2new, 
			Standard_Real& V1new, 
			Standard_Real& V2new, 
			Standard_Boolean& NoIntersection);

static 
  void EstLimForInfOffs(const gp_Lin&   Line,
			const TheSurface& surface, 
			const Standard_Integer nbsu, 
			const Standard_Boolean U1inf, 
			const Standard_Boolean U2inf, 
			const Standard_Boolean V1inf, 
			const Standard_Boolean V2inf, 
			Standard_Real& U1new, 
			Standard_Real& U2new, 
			Standard_Real& V1new, 
			Standard_Real& V2new, 
			Standard_Boolean& NoIntersection);

static
  void EstLimForInfSurf(Standard_Real& U1new, 
			Standard_Real& U2new, 
			Standard_Real& V1new, 
			Standard_Real& V2new);

static
  void SectionPointToParameters(const Intf_SectionPoint& Sp,
				const IntCurveSurface_ThePolyhedron& Surf,
				const IntCurveSurface_ThePolygon&    Curv,
				Standard_Real& u,
				Standard_Real& v,
				Standard_Real& w);

static 
  void IntCurveSurface_ComputeTransitions(const TheCurve& curve,
					  const Standard_Real w,
					  IntCurveSurface_TransitionOnCurve&   TransOnCurve,
					  const TheSurface& surface,
					  const Standard_Real u,
					  const Standard_Real v);

static 
  void IntCurveSurface_ComputeParamsOnQuadric(const TheSurface& surface,
					      const gp_Pnt& P,
					      Standard_Real& u,
					      Standard_Real& v);

static 
  void ProjectIntersectAndEstLim(const gp_Lin&        theLine,
				 const gp_Pln&        thePln,
				 const ProjLib_Plane& theBasCurvProj,
				 Standard_Real&       theVmin,
				 Standard_Real&       theVmax,
				 Standard_Boolean&    theNoIntersection);

//=======================================================================
//function : IntCurveSurface_Inter
//purpose  : 
//=======================================================================
IntCurveSurface_Inter::IntCurveSurface_Inter() 
{ 
}
//=======================================================================
//function : DoSurface
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::DoSurface(const TheSurface&   surface,
				      const Standard_Real u0,
				      const Standard_Real u1,
				      const Standard_Real v0,
				      const Standard_Real v1,
				      TColgp_Array2OfPnt& pntsOnSurface,
				      Bnd_Box&            boxSurface,
				      Standard_Real&      gap)
{
  Standard_Integer iU = 0, iV = 0;
  Standard_Real U = 0., V = 0;
// modified by NIZHNY-MKK  Mon Oct  3 17:38:45 2005
//   Standard_Real dU = fabs(u1-u0)/50., dV = fabs(v1-v0)/50.;
  Standard_Real dU = (u1-u0)/50., dV = (v1-v0)/50.;
  gp_Pnt aPnt;

  for(iU = 0; iU < 50; iU++) {
    
    if(iU == 0)
      U = u0;
    else if(iU == 49)
      U = u1;
    else 
      U = u0 + dU * ((Standard_Real)iU);
    
    for(iV = 0; iV < 50; iV++) {

      if(iV == 0)
        V = v0;
      else if(iV == 49)
        V = v1;
      else
        V = v0 + dV * ((Standard_Real)iV);

      TheSurfaceTool::D0(surface,U,V,aPnt);
      boxSurface.Add(aPnt);
      pntsOnSurface.SetValue(iU+1,iV+1,aPnt);
    }
  }
  Standard_Real Ures = TheSurfaceTool::UResolution(surface,dU);
  Standard_Real Vres = TheSurfaceTool::VResolution(surface,dV);
  gap = Max(Ures,Vres);
}

//=======================================================================
//function : DoNewBounds
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::DoNewBounds(
					const TheSurface&           surface,
					const Standard_Real         u0,
					const Standard_Real         u1,
					const Standard_Real         v0,
					const Standard_Real         v1,
					const TColgp_Array2OfPnt&   pntsOnSurface,
					const TColStd_Array1OfReal& X,
					const TColStd_Array1OfReal& Y,
					const TColStd_Array1OfReal& Z,
					TColStd_Array1OfReal&       Bounds)
{
  Bounds.SetValue(1,u0);
  Bounds.SetValue(2,u1);
  Bounds.SetValue(3,v0);
  Bounds.SetValue(4,v1);

  Standard_Boolean isUClosed = (TheSurfaceTool::IsUClosed(surface) || TheSurfaceTool::IsUPeriodic(surface));
  Standard_Boolean isVClosed = (TheSurfaceTool::IsVClosed(surface) || TheSurfaceTool::IsVPeriodic(surface));
  Standard_Boolean checkU = (isUClosed) ? Standard_False : Standard_True;
  Standard_Boolean checkV = (isVClosed) ? Standard_False : Standard_True;

  Standard_Integer i = 0, j = 0, k = 0, iU = 0, iV = 0;
  Standard_Integer iUmin = 50, iVmin = 50, iUmax = 1, iVmax = 1;

  for(i = 1; i <= 2; i++) {
    for(j = 1; j <= 2; j++) {
      for(k = 1; k <= 2; k++) {
        gp_Pnt aPoint(X(i),Y(j),Z(k));
        Standard_Real DistMin = 1.e+100;
        Standard_Integer diU = 0, diV = 0;
        for(iU = 1; iU <= 50; iU++) {
          for(iV = 1; iV <= 50; iV++) {
            const gp_Pnt aP = pntsOnSurface.Value(iU,iV);
            Standard_Real dist = aP.SquareDistance(aPoint);
            if(dist < DistMin) {
              DistMin = dist;
              diU = iU;
              diV = iV;
            }
          }
        }
        if(diU > 0 && diU < iUmin) iUmin = diU;
        if(diU > 0 && diU > iUmax) iUmax = diU;
        if(diV > 0 && diV < iVmin) iVmin = diV;
        if(diV > 0 && diV > iVmax) iVmax = diV;
      }
    }
  }

// modified by NIZHNY-MKK  Mon Oct  3 17:38:43 2005
//   Standard_Real dU = fabs(u1-u0)/50., dV = fabs(v1-v0)/50.;
  Standard_Real dU = (u1-u0)/50., dV = (v1-v0)/50.;

  Standard_Real USmin = u0 + dU * ((Standard_Real)(iUmin - 1));
  Standard_Real USmax = u0 + dU * ((Standard_Real)(iUmax - 1));
  Standard_Real VSmin = v0 + dV * ((Standard_Real)(iVmin - 1));
  Standard_Real VSmax = v0 + dV * ((Standard_Real)(iVmax - 1));

  if(USmin > USmax) {
    Standard_Real tmp = USmax;
    USmax = USmin;
    USmin = tmp;
  }
  if(VSmin > VSmax) {
    Standard_Real tmp = VSmax;
    VSmax = VSmin;
    VSmin = tmp;
  }

  USmin -= 1.5*dU;
  if(USmin < u0) USmin = u0;
  USmax += 1.5*dU;
  if(USmax > u1) USmax = u1;
  VSmin -= 1.5*dV;
  if(VSmin < v0) VSmin = v0;
  VSmax += 1.5*dV;
  if(VSmax > v1) VSmax = v1;

  if(checkU) {
    Bounds.SetValue(1,USmin);
    Bounds.SetValue(2,USmax);
  }
  if(checkV) {
    Bounds.SetValue(3,VSmin);
    Bounds.SetValue(4,VSmax);
  }
}

//=======================================================================
//function : Perform
//purpose  : Decompose la surface si besoin est 
//=======================================================================
void IntCurveSurface_Inter::Perform(const TheCurve&   curve,
                                    const TheSurface& surface)
{
  ResetFields();
  done = Standard_True;
  Standard_Integer NbUOnS = TheSurfaceTool::NbUIntervals(surface,GeomAbs_C2);
  Standard_Integer NbVOnS = TheSurfaceTool::NbVIntervals(surface,GeomAbs_C2);
  Standard_Real U0,U1,V0,V1; 

  if(NbUOnS > 1)
  {
    TColStd_Array1OfReal TabU(1,NbUOnS+1);
    TheSurfaceTool::UIntervals(surface,TabU,GeomAbs_C2);
    for(Standard_Integer iu = 1;iu <= NbUOnS; iu++)
    {
      U0 = TabU.Value(iu);
      U1 = TabU.Value(iu+1);
      if(NbVOnS > 1)
      {
        TColStd_Array1OfReal TabV(1,NbVOnS+1);
        TheSurfaceTool::VIntervals(surface,TabV,GeomAbs_C2);
        for(Standard_Integer iv = 1;iv <= NbVOnS; iv++)
        {
          // More than one interval on U and V param space.
          V0 = TabV.Value(iv);
          V1 = TabV.Value(iv+1);
          Perform(curve,surface,U0,V0,U1,V1);
        }
      }
      else
      {
        // More than one interval only on U param space.
        V0 = TheSurfaceTool::FirstVParameter(surface);
        V1 = TheSurfaceTool::LastVParameter(surface);
        Perform(curve,surface,U0,V0,U1,V1);
      }
    }
  }
  else if(NbVOnS > 1)
  {
    // More than one interval only on V param space.
    U0 = TheSurfaceTool::FirstUParameter(surface);
    U1 = TheSurfaceTool::LastUParameter(surface);   
    TColStd_Array1OfReal TabV(1,NbVOnS+1);
    TheSurfaceTool::VIntervals(surface,TabV,GeomAbs_C2);
    for(Standard_Integer iv = 1;iv <= NbVOnS; iv++)
    {
      V0 = TabV.Value(iv);
      V1 = TabV.Value(iv+1);
      Perform(curve,surface,U0,V0,U1,V1);
    }
  }
  else
  {
    // One interval on U and V param space.
    V0 = TheSurfaceTool::FirstVParameter(surface);
    V1 = TheSurfaceTool::LastVParameter(surface);
    U0 = TheSurfaceTool::FirstUParameter(surface);
    U1 = TheSurfaceTool::LastUParameter(surface);

    Perform(curve,surface,U0,V0,U1,V1);
  }
}
//=======================================================================
//function : Perform
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::Perform(const TheCurve&   curve,
                                    const TheSurface& surface,
                                    const Standard_Real U1,const Standard_Real V1,
                                    const Standard_Real U2,const Standard_Real V2)
{
  // Protection from double type overflow.
  // This may happen inside square magnitude computation based on normal,
  // which was computed on bound parameteres (bug26525).
  Standard_Real UU1 = U1, UU2 = U2, VV1 = V1, VV2 = V2;
  if (U1 < -1.0e50)
    UU1 = -1.0e50;
  if (U2 >  1.0e50)
    UU2 = 1.0e50;
  if (V1 < -1.0e50)
    VV1 = -1.0e50;
  if (V2 >  1.0e50)
    VV2 = 1.0e50;

  GeomAbs_CurveType CurveType = TheCurveTool::GetType(curve);
  
  switch(CurveType) { 
  case GeomAbs_Line:  
    { 
      PerformConicSurf(TheCurveTool::Line(curve),curve,surface,UU1,VV1,UU2,VV2);
      break;
    }
  case GeomAbs_Circle: 
    { 
      PerformConicSurf(TheCurveTool::Circle(curve),curve,surface,UU1,VV1,UU2,VV2);
      break;
    }
  case GeomAbs_Ellipse: 
    { 
      PerformConicSurf(TheCurveTool::Ellipse(curve),curve,surface,UU1,VV1,UU2,VV2);
      break;
    }    
  case GeomAbs_Parabola:  
    {
      PerformConicSurf(TheCurveTool::Parabola(curve),curve,surface,UU1,VV1,UU2,VV2);
      break;
    }
  case GeomAbs_Hyperbola: 
    {
      PerformConicSurf(TheCurveTool::Hyperbola(curve),curve,surface,UU1,VV1,UU2,VV2);
      break;
    }
  default:    
    {
      Standard_Integer nbIntervalsOnCurve = TheCurveTool::NbIntervals(curve,GeomAbs_C2);
      GeomAbs_SurfaceType SurfaceType = TheSurfaceTool::GetType(surface);
      if(   (SurfaceType != GeomAbs_Plane) 
	 && (SurfaceType != GeomAbs_Cylinder)
	 && (SurfaceType != GeomAbs_Cone) 
	 && (SurfaceType != GeomAbs_Sphere)) { 
	
	if(nbIntervalsOnCurve > 1) { 
	  TColStd_Array1OfReal TabW(1,nbIntervalsOnCurve+1);
	  TheCurveTool::Intervals(curve,TabW,GeomAbs_C2);
	  for(Standard_Integer i = 1; i<=nbIntervalsOnCurve; i++) { 
	    Standard_Real u1,u2;
	    u1 = TabW.Value(i);
	    u2 = TabW.Value(i+1);

	    Handle(TColStd_HArray1OfReal) aPars;
	    Standard_Real defl = 0.1;
	    Standard_Integer NbMin = 10;
	    TheCurveTool::SamplePars(curve, u1, u2, defl, NbMin, aPars);

// 	    IntCurveSurface_ThePolygon  polygon(curve,u1,u2,TheCurveTool::NbSamples(curve,u1,u2));
	    IntCurveSurface_ThePolygon  polygon(curve, aPars->Array1());
	    InternalPerform(curve,polygon,surface,UU1,VV1,UU2,VV2);
	  }
	}
	else {
	  Standard_Real u1,u2;
	  u1 = TheCurveTool::FirstParameter(curve);
	  u2 = TheCurveTool::LastParameter(curve);

	  Handle(TColStd_HArray1OfReal) aPars;
	  Standard_Real defl = 0.1;
	  Standard_Integer NbMin = 10;
	  TheCurveTool::SamplePars(curve, u1, u2, defl, NbMin, aPars);

// 	  IntCurveSurface_ThePolygon       polygon(curve,TheCurveTool::NbSamples(curve,u1,u2));
	  IntCurveSurface_ThePolygon  polygon(curve, aPars->Array1());
	  InternalPerform(curve,polygon,surface,UU1,VV1,UU2,VV2);
	}
      }
      else {   //-- la surface est une quadrique 
	InternalPerformCurveQuadric(curve,surface);
      }
    }
  }
}
//=======================================================================
//function : Perform
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::Perform(const TheCurve&   curve,
				    const IntCurveSurface_ThePolygon& polygon,
				    const TheSurface& surface) {
  ResetFields();
  done = Standard_True;
  Standard_Real u1,v1,u2,v2;
  u1 = TheSurfaceTool::FirstUParameter(surface);
  v1 = TheSurfaceTool::FirstVParameter(surface);
  u2 = TheSurfaceTool::LastUParameter(surface);
  v2 = TheSurfaceTool::LastVParameter(surface);
  Standard_Integer nbsu,nbsv;
  nbsu = TheSurfaceTool::NbSamplesU(surface,u1,u2);
  nbsv = TheSurfaceTool::NbSamplesV(surface,v1,v2);
  if(nbsu>40) nbsu=40;
  if(nbsv>40) nbsv=40;
  IntCurveSurface_ThePolyhedron    polyhedron(surface,nbsu,nbsv,u1,v1,u2,v2);
  Perform(curve,polygon,surface,polyhedron);
}
//=======================================================================
//function : Perform
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::Perform(const TheCurve&   curve,
				    const TheSurface& surface,
				    const IntCurveSurface_ThePolyhedron& polyhedron) {
  ResetFields();
  done = Standard_True;
  Standard_Real u1 = TheCurveTool::FirstParameter(curve);
  Standard_Real u2 = TheCurveTool::LastParameter(curve);
  IntCurveSurface_ThePolygon polygon(curve,TheCurveTool::NbSamples(curve,u1,u2));
  Perform(curve,polygon,surface,polyhedron);
}
//=======================================================================
//function : Perform
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::Perform(const TheCurve&       curve,
				    const IntCurveSurface_ThePolygon&     polygon,
				    const TheSurface&     surface,
				    const IntCurveSurface_ThePolyhedron&  polyhedron) {
  ResetFields();
  done = Standard_True;
  Standard_Real u1,v1,u2,v2;
  u1 = TheSurfaceTool::FirstUParameter(surface);
  v1 = TheSurfaceTool::FirstVParameter(surface);
  u2 = TheSurfaceTool::LastUParameter(surface);
  v2 = TheSurfaceTool::LastVParameter(surface);
  InternalPerform(curve,polygon,surface,polyhedron,u1,v1,u2,v2);
}

//=======================================================================
//function : Perform
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::Perform(const TheCurve&       curve,
				    const IntCurveSurface_ThePolygon&     polygon,
				    const TheSurface&     surface,
				    const IntCurveSurface_ThePolyhedron&  polyhedron,
				    Bnd_BoundSortBox& BndBSB) {
  ResetFields();
  done = Standard_True;
  Standard_Real u1,v1,u2,v2;
  u1 = TheSurfaceTool::FirstUParameter(surface);
  v1 = TheSurfaceTool::FirstVParameter(surface);
  u2 = TheSurfaceTool::LastUParameter(surface);
  v2 = TheSurfaceTool::LastVParameter(surface);
  InternalPerform(curve,polygon,surface,polyhedron,u1,v1,u2,v2,BndBSB);
}
//=======================================================================
//function : InternalPerform
//purpose  : C a l c u l   d u   p o i n t   a p p r o c h e           
//==              p u i s   d u   p o i n t   E x a c t  
//=======================================================================
void IntCurveSurface_Inter::InternalPerform(const TheCurve&       curve,
					    const IntCurveSurface_ThePolygon&     polygon,
					    const TheSurface&     surface,
					    const IntCurveSurface_ThePolyhedron&  polyhedron,
					    const Standard_Real u0,
					    const Standard_Real v0,
					    const Standard_Real u1, 
					    const Standard_Real v1,
					    Bnd_BoundSortBox& BSB) {
  IntCurveSurface_TheInterference  interference(polygon,polyhedron,BSB);
  IntCurveSurface_TheCSFunction    theicsfunction(surface,curve);
  IntCurveSurface_TheExactInter    intersectionExacte(theicsfunction,TOLTANGENCY);
  math_FunctionSetRoot rsnld(intersectionExacte.Function());

//  Standard_Real    u,v,w,winit;
  Standard_Real    u,v,w;
  gp_Pnt P;
  Standard_Real winf = polygon.InfParameter();
  Standard_Real wsup = polygon.SupParameter();
  Standard_Integer NbSectionPoints = interference.NbSectionPoints();
  Standard_Integer NbTangentZones  = interference.NbTangentZones();


  //-- Les interferences renvoient parfois de nombreuses fois (>20) les memes points 
  
  Standard_Integer i,NbStartPoints=NbSectionPoints;
  for(i=1; i<= NbTangentZones; i++) {
    const Intf_TangentZone& TZ = interference.ZoneValue(i);
    Standard_Integer nbpnts = TZ.NumberOfPoints();
    NbStartPoints+=nbpnts;
  }
  
  if(NbStartPoints) { 
    Standard_Real *TabU = new Standard_Real [NbStartPoints+1];
    Standard_Real *TabV = new Standard_Real [NbStartPoints+1];
    Standard_Real *TabW = new Standard_Real [NbStartPoints+1];
    Standard_Integer IndexPoint=0;
    
    for(i=1; i<= NbSectionPoints; i++) {
      const Intf_SectionPoint& SP = interference.PntValue(i);
      SectionPointToParameters(SP,polyhedron,polygon,u,v,w);
      TabU[IndexPoint]=u;
      TabV[IndexPoint]=v;
      TabW[IndexPoint]=w;
      IndexPoint++;
    }
    for(i=1; i<= NbTangentZones; i++) {
      const Intf_TangentZone& TZ = interference.ZoneValue(i);
      Standard_Integer nbpnts = TZ.NumberOfPoints();
      for(Standard_Integer j=1; j<=nbpnts; j++) { 
	const Intf_SectionPoint& SP = TZ.GetPoint(j);
	SectionPointToParameters(SP,polyhedron,polygon,u,v,w);  
	TabU[IndexPoint]=u;
	TabV[IndexPoint]=v;
	TabW[IndexPoint]=w;
	IndexPoint++;
      }
    }
    
    //-- Tri
    Standard_Real su=0,sv=0,sw=0,ptol;
    ptol = 10*Precision::PConfusion();
    
    //-- Tri suivant la variable W 
    Standard_Boolean Triok;
    do { 
      Triok=Standard_True;
      Standard_Integer im1;
      for(i=1,im1=0;i<NbStartPoints;im1++,i++) {       
	if(TabW[i] < TabW[im1]) { 
	  Standard_Real t=TabW[i]; TabW[i]=TabW[im1]; TabW[im1]=t;
	  t=TabU[i]; TabU[i]=TabU[im1]; TabU[im1]=t;
	  t=TabV[i]; TabV[i]=TabV[im1]; TabV[im1]=t;
	  Triok=Standard_False;
	}
      }
    }
    while(Triok==Standard_False);
    
    //-- On trie pour des meme W suivant U
    do { 
      Triok=Standard_True;
      Standard_Integer im1;
      for(i=1,im1=0;i<NbStartPoints;im1++,i++) {       
// modified by NIZHNY-MKK  Mon Oct  3 17:38:49 2005
// 	if(Abs(TabW[i]-TabW[im1])<ptol) { 
	if((TabW[i]-TabW[im1])<ptol) { 
	  TabW[i]=TabW[im1];
	  if(TabU[i] < TabU[im1]) { 
	    Standard_Real t=TabU[i]; TabU[i]=TabU[im1]; TabU[im1]=t;
	    t=TabV[i]; TabV[i]=TabV[im1]; TabV[im1]=t;
	    Triok=Standard_False;
	  }
	}
      }
    }
    while(Triok==Standard_False);
    
    //-- On trie pour des meme U et W suivant V
    do { 
      Triok=Standard_True;
      Standard_Integer im1;
      for(i=1,im1=0;i<NbStartPoints;im1++,i++) {       
// modified by NIZHNY-MKK  Mon Oct  3 17:38:52 2005
// 	if((Abs(TabW[i]-TabW[im1])<ptol) && (Abs(TabU[i]-TabU[im1])<ptol)) { 
	if(((TabW[i]-TabW[im1])<ptol) && ((TabU[i]-TabU[im1])<ptol)) { 
	  TabU[i]=TabU[im1];
	  if(TabV[i] < TabV[im1]) { 
	    Standard_Real t=TabV[i]; TabV[i]=TabV[im1]; TabV[im1]=t;
	    Triok=Standard_False;
	  }
	}
      }
    }
    while(Triok==Standard_False);
    
    
    for(i=0;i<NbStartPoints; i++) { 
      u=TabU[i]; v=TabV[i]; w=TabW[i];
      if(i==0) {
	su=u-1; 
      }
      if(Abs(u-su)>ptol || Abs(v-sv)>ptol || Abs(w-sw)>ptol) { 
	intersectionExacte.Perform(u,v,w,rsnld,u0,u1,v0,v1,winf,wsup);
	if(intersectionExacte.IsDone()) { 
	  if(!intersectionExacte.IsEmpty()) { 
	    P=intersectionExacte.Point();
	    w=intersectionExacte.ParameterOnCurve();
	    intersectionExacte.ParameterOnSurface(u,v);
	    AppendPoint(curve,w,surface,u,v);
	  }
	}
      }
      su=TabU[i]; sv=TabV[i]; sw=TabW[i];
    }
    delete [] TabW;
    delete [] TabV;
    delete [] TabU;
  }
}

//=======================================================================
//function : InternalPerform
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::InternalPerform(const TheCurve&       curve,
					    const IntCurveSurface_ThePolygon&     polygon,
					    const TheSurface&     surface,
					    const IntCurveSurface_ThePolyhedron&  polyhedron,
					    const Standard_Real u0,
					    const Standard_Real v0,
					    const Standard_Real u1, 
					    const Standard_Real v1) { 
  IntCurveSurface_TheInterference  interference(polygon,polyhedron);
  IntCurveSurface_TheCSFunction    theicsfunction(surface,curve);
  IntCurveSurface_TheExactInter    intersectionExacte(theicsfunction,TOLTANGENCY);
  math_FunctionSetRoot rsnld(intersectionExacte.Function());

//  Standard_Real    u,v,w,winit;
  Standard_Real    u,v,w;
  gp_Pnt P;
  Standard_Real winf = polygon.InfParameter();
  Standard_Real wsup = polygon.SupParameter();
  Standard_Integer NbSectionPoints = interference.NbSectionPoints();
  Standard_Integer NbTangentZones  = interference.NbTangentZones();


  //-- Les interferences renvoient parfois de nombreuses fois (>20) les memes points 
  
  Standard_Integer i,NbStartPoints=NbSectionPoints;
  for(i=1; i<= NbTangentZones; i++) {
    const Intf_TangentZone& TZ = interference.ZoneValue(i);
    Standard_Integer nbpnts = TZ.NumberOfPoints();
    NbStartPoints+=nbpnts;
  }
  
  if(NbStartPoints) { 
    Standard_Real *TabU = new Standard_Real [NbStartPoints+1];
    Standard_Real *TabV = new Standard_Real [NbStartPoints+1];
    Standard_Real *TabW = new Standard_Real [NbStartPoints+1];
    Standard_Integer IndexPoint=0;
    
    for(i=1; i<= NbSectionPoints; i++) {
      const Intf_SectionPoint& SP = interference.PntValue(i);
      SectionPointToParameters(SP,polyhedron,polygon,u,v,w);
      TabU[IndexPoint]=u;
      TabV[IndexPoint]=v;
      TabW[IndexPoint]=w;
      IndexPoint++;
    }
    for(i=1; i<= NbTangentZones; i++) {
      const Intf_TangentZone& TZ = interference.ZoneValue(i);
      Standard_Integer nbpnts = TZ.NumberOfPoints();
      for(Standard_Integer j=1; j<=nbpnts; j++) { 
	const Intf_SectionPoint& SP = TZ.GetPoint(j);
	SectionPointToParameters(SP,polyhedron,polygon,u,v,w);  
	TabU[IndexPoint]=u;
	TabV[IndexPoint]=v;
	TabW[IndexPoint]=w;
	IndexPoint++;
      }
    }
    
    //-- Tri
    Standard_Real su=0,sv=0,sw=0,ptol;
    ptol = 10*Precision::PConfusion();
    
    //-- Tri suivant la variable W 
    Standard_Boolean Triok;
    do { 
      Triok=Standard_True;
      Standard_Integer im1;
      for(i=1,im1=0;i<NbStartPoints;im1++,i++) {       
	if(TabW[i] < TabW[im1]) { 
	  Standard_Real t=TabW[i]; TabW[i]=TabW[im1]; TabW[im1]=t;
	  t=TabU[i]; TabU[i]=TabU[im1]; TabU[im1]=t;
	  t=TabV[i]; TabV[i]=TabV[im1]; TabV[im1]=t;
	  Triok=Standard_False;
	}
      }
    }
    while(Triok==Standard_False);
    
    //-- On trie pour des meme W suivant U
    do { 
      Triok=Standard_True;
      Standard_Integer im1;
      for(i=1,im1=0;i<NbStartPoints;im1++,i++) {       
// modified by NIZHNY-MKK  Mon Oct  3 17:38:56 2005
// 	if(Abs(TabW[i]-TabW[im1])<ptol) { 
	if((TabW[i]-TabW[im1])<ptol) { 
	  TabW[i]=TabW[im1];
	  if(TabU[i] < TabU[im1]) { 
	    Standard_Real t=TabU[i]; TabU[i]=TabU[im1]; TabU[im1]=t;
	    t=TabV[i]; TabV[i]=TabV[im1]; TabV[im1]=t;
	    Triok=Standard_False;
	  }
	}
      }
    }
    while(Triok==Standard_False);
    
    //-- On trie pour des meme U et W suivant V
    do { 
      Triok=Standard_True;
      Standard_Integer im1;
      for(i=1,im1=0;i<NbStartPoints;im1++,i++) {       
// modified by NIZHNY-MKK  Mon Oct  3 17:38:58 2005
// 	if((Abs(TabW[i]-TabW[im1])<ptol) && (Abs(TabU[i]-TabU[im1])<ptol)) { 
	if(((TabW[i]-TabW[im1])<ptol) && ((TabU[i]-TabU[im1])<ptol)) { 
	  TabU[i]=TabU[im1];
	  if(TabV[i] < TabV[im1]) { 
	    Standard_Real t=TabV[i]; TabV[i]=TabV[im1]; TabV[im1]=t;
	    Triok=Standard_False;
	  }
	}
      }
    }
    while(Triok==Standard_False);
    
    
    for(i=0;i<NbStartPoints; i++) { 
      u=TabU[i]; v=TabV[i]; w=TabW[i];
      if(i==0) {
	su=u-1; 
      }
      if(Abs(u-su)>ptol || Abs(v-sv)>ptol || Abs(w-sw)>ptol) { 
	intersectionExacte.Perform(u,v,w,rsnld,u0,u1,v0,v1,winf,wsup);
	if(intersectionExacte.IsDone()) { 
	  if(!intersectionExacte.IsEmpty()) { 
	    P=intersectionExacte.Point();
	    w=intersectionExacte.ParameterOnCurve();
	    intersectionExacte.ParameterOnSurface(u,v);
	    AppendPoint(curve,w,surface,u,v);
	  }
	}
      }
      su=TabU[i]; sv=TabV[i]; sw=TabW[i];
    }
    delete [] TabW;
    delete [] TabV;
    delete [] TabU;
  }
}
//=======================================================================
//function : InternalPerformCurveQuadric
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::InternalPerformCurveQuadric(const TheCurve&                 curve,
							const TheSurface&               surface) { 
  IntCurveSurface_TheQuadCurvExactInter QuadCurv(surface,curve);  
  if(QuadCurv.IsDone()) { 
    Standard_Integer NbRoots = QuadCurv.NbRoots();
    Standard_Real u,v,w;
    for(Standard_Integer i = 1; i<= NbRoots; i++) { 
      w = QuadCurv.Root(i); 
      IntCurveSurface_ComputeParamsOnQuadric(surface,TheCurveTool::Value(curve,w),u,v);
      AppendPoint(curve,w,surface,u,v); 
    }
    //-- Intervals non traites .............................................
  }
}

//=======================================================================
//function : InternalPerform
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::InternalPerform(const TheCurve&       curve,
					    const IntCurveSurface_ThePolygon&  polygon,
					    const TheSurface&     surface,
					    const Standard_Real U1,
					    const Standard_Real V1,
					    const Standard_Real U2,
					    const Standard_Real V2) {
  GeomAbs_SurfaceType SurfaceType = TheSurfaceTool::GetType(surface);
  if(   (SurfaceType != GeomAbs_Plane) 
     && (SurfaceType != GeomAbs_Cylinder)
     && (SurfaceType != GeomAbs_Cone) 
     && (SurfaceType != GeomAbs_Sphere) ) {
    if(SurfaceType != GeomAbs_BSplineSurface) {
      Standard_Integer nbsu,nbsv;
      nbsu = TheSurfaceTool::NbSamplesU(surface,U1,U2);
      nbsv = TheSurfaceTool::NbSamplesV(surface,V1,V2);
      if(nbsu>40) nbsu=40;
      if(nbsv>40) nbsv=40;
      IntCurveSurface_ThePolyhedron polyhedron(surface,nbsu,nbsv,U1,V1,U2,V2);
      InternalPerform(curve,polygon,surface,polyhedron,U1,V1,U2,V2); 
    }
    else {
      Handle(Adaptor3d_Surface) aS = TheSurfaceTool::UTrim(surface, U1, U2, 1.e-9);
      aS = aS->VTrim(V1, V2, 1.e-9);
      Handle(Adaptor3d_TopolTool) aTopTool = new Adaptor3d_TopolTool(aS);
      Standard_Real defl = 0.1;
      aTopTool->SamplePnts(defl, 10, 10);

      Standard_Integer nbpu = aTopTool->NbSamplesU();
      Standard_Integer nbpv = aTopTool->NbSamplesV();
      TColStd_Array1OfReal Upars(1, nbpu), Vpars(1, nbpv);
      aTopTool->UParameters(Upars);
      aTopTool->VParameters(Vpars);

      IntCurveSurface_ThePolyhedron polyhedron(surface,Upars, Vpars);
      InternalPerform(curve,polygon,surface,polyhedron,U1,V1,U2,V2); 
    }
  }
  else {
    IntCurveSurface_TheQuadCurvExactInter QuadCurv(surface,curve);  
    if(QuadCurv.IsDone()) { 
      Standard_Integer NbRoots = QuadCurv.NbRoots();
      Standard_Real u,v,w;
      for(Standard_Integer i = 1; i<= NbRoots; i++) { 
	w = QuadCurv.Root(i); 
	IntCurveSurface_ComputeParamsOnQuadric(surface,TheCurveTool::Value(curve,w),u,v);
	AppendPoint(curve,w,surface,u,v); 
      }
      //-- Intervalles non traites .............................................
    }
  } //-- Fin : la Surface  est une quadrique
}
//=======================================================================
//function : PerformConicSurf
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::PerformConicSurf(const gp_Lin&   Line,
					     const TheCurve&       curve,
					     const TheSurface&     surface,
					     const Standard_Real U1,
					     const Standard_Real V1,
					     const Standard_Real U2,
					     const Standard_Real V2) {
  

  GeomAbs_SurfaceType SurfaceType = TheSurfaceTool::GetType(surface);
  Standard_Boolean isAnaProcessed = Standard_True;
  switch(SurfaceType) { 
  case GeomAbs_Plane: 
    {
      IntAna_IntConicQuad LinPlane(Line,TheSurfaceTool::Plane(surface),TOLERANCE_ANGULAIRE);
      AppendIntAna(curve,surface,LinPlane);
      break;
    }
  case GeomAbs_Cylinder:
    {
      IntAna_IntConicQuad LinCylinder(Line,TheSurfaceTool::Cylinder(surface));
      AppendIntAna(curve,surface,LinCylinder);
      break;
    }
  case GeomAbs_Sphere:
    {
      IntAna_IntConicQuad LinSphere(Line,TheSurfaceTool::Sphere(surface));
      AppendIntAna(curve,surface,LinSphere);
      break;
    }
  case GeomAbs_Torus: 
    {
      IntAna_IntLinTorus intlintorus(Line, TheSurfaceTool::Torus(surface));
      if (intlintorus.IsDone()) {
        Standard_Integer nbp = intlintorus.NbPoints();
        Standard_Real fi, theta, w;
        for (Standard_Integer i = 1; i <= nbp; i++) {
          const gp_Pnt aDebPnt(intlintorus.Value(i));
          (void)aDebPnt;
          w = intlintorus.ParamOnLine(i);
          intlintorus.ParamOnTorus(i, fi, theta);
          AppendPoint(curve, w, surface, fi, theta);
        }
      }
      else
        isAnaProcessed = Standard_False;
      break;
    }
  case GeomAbs_Cone:
    {
      const Standard_Real correction = 1.E+5*Precision::Angular();
      gp_Cone cn = TheSurfaceTool::Cone(surface);
      if(Abs(cn.SemiAngle()) < M_PI/2.0 - correction) {
        IntAna_IntConicQuad LinCone(Line, cn);
        AppendIntAna(curve, surface, LinCone);
      }
      else
        isAnaProcessed = Standard_False;
      break;
    }
  default:
    isAnaProcessed = Standard_False;
  }
  if (!isAnaProcessed)
  {
    Standard_Integer nbsu,nbsv;
    nbsu = TheSurfaceTool::NbSamplesU(surface,U1,U2);
    nbsv = TheSurfaceTool::NbSamplesV(surface,V1,V2);

    Standard_Boolean U1inf = Precision::IsInfinite(U1);
    Standard_Boolean U2inf = Precision::IsInfinite(U2);
    Standard_Boolean V1inf = Precision::IsInfinite(V1);
    Standard_Boolean V2inf = Precision::IsInfinite(V2);

    Standard_Real U1new=U1, U2new=U2, V1new=V1, V2new=V2;

    Standard_Boolean NoIntersection = Standard_False;

    if(U1inf || U2inf || V1inf || V2inf ) {

      if(SurfaceType == GeomAbs_SurfaceOfExtrusion) {

        EstLimForInfExtr(Line, surface, Standard_False, nbsu,
                         U1inf, U2inf, V1inf, V2inf,
                         U1new, U2new, V1new, V2new, NoIntersection);

      }
      else if (SurfaceType == GeomAbs_SurfaceOfRevolution) {

        EstLimForInfRevl(Line, surface,
                         U1inf, U2inf, V1inf, V2inf,
                         U1new, U2new, V1new, V2new, NoIntersection);

      }
      else if (SurfaceType == GeomAbs_OffsetSurface) {

        EstLimForInfOffs(Line, surface, nbsu,
                         U1inf, U2inf, V1inf, V2inf,
                         U1new, U2new, V1new, V2new, NoIntersection);
      }
      else {

        EstLimForInfSurf(U1new, U2new, V1new, V2new);
      }

    }


    if(NoIntersection) return;


    // modified by NIZHNY-OFV  Mon Aug 20 14:56:47 2001 (60963 begin)
    if(nbsu<20) nbsu=20;
    if(nbsv<20) nbsv=20;
    // modified by NIZHNY-OFV  Mon Aug 20 14:57:06 2001 (60963 end)
    IntCurveSurface_ThePolyhedron polyhedron(surface,nbsu,nbsv,U1new,V1new,U2new,V2new);
    Intf_Tool                     bndTool;
    Bnd_Box                       boxLine;
    bndTool.LinBox(Line,polyhedron.Bounding(),boxLine);
    for(Standard_Integer nbseg=1; nbseg<= bndTool.NbSegments(); nbseg++) { 
      Standard_Real pinf = bndTool.BeginParam(nbseg);
      Standard_Real psup = bndTool.EndParam(nbseg);
      if((psup - pinf)<1e-10) { pinf-=1e-10; psup+=1e-10; } 
      IntCurveSurface_ThePolygon polygon(curve, pinf,psup,2);
      InternalPerform(curve,polygon,surface,polyhedron,U1new,V1new,U2new,V2new);
    }
  }
}
//=======================================================================
//function : PerformConicSurf
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::PerformConicSurf(const gp_Circ&        Circle,
					     const TheCurve&       curve,
					     const TheSurface&     surface,
					     const Standard_Real U1,
					     const Standard_Real V1,
					     const Standard_Real U2,
					     const Standard_Real V2) { 
  
  GeomAbs_SurfaceType SurfaceType = TheSurfaceTool::GetType(surface);
  switch(SurfaceType) { 
  case GeomAbs_Plane: 
    {
      IntAna_IntConicQuad CircPlane(Circle,TheSurfaceTool::Plane(surface),TOLERANCE_ANGULAIRE,TOLERANCE);
      AppendIntAna(curve,surface,CircPlane);
      break;
    }
  case GeomAbs_Cylinder:
    {
      IntAna_IntConicQuad CircCylinder(Circle,TheSurfaceTool::Cylinder(surface));
      AppendIntAna(curve,surface,CircCylinder);
      break;
    }
  case GeomAbs_Cone:
    {
      IntAna_IntConicQuad CircCone(Circle,TheSurfaceTool::Cone(surface));
      AppendIntAna(curve,surface,CircCone);
      break;
    }   
  case GeomAbs_Sphere:
    {
      IntAna_IntConicQuad CircSphere(Circle,TheSurfaceTool::Sphere(surface));
      AppendIntAna(curve,surface,CircSphere);
      break;
    }
  default: 
    {
      IntCurveSurface_ThePolygon polygon(curve,NBSAMPLESONCIRCLE);
      InternalPerform(curve,polygon,surface,U1,V1,U2,V2);
    }
  }
}
//=======================================================================
//function : PerformConicSurf
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::PerformConicSurf(const gp_Elips&       Ellipse,
					     const TheCurve&       curve,
					     const TheSurface&     surface,
					     const Standard_Real U1,
					     const Standard_Real V1,
					     const Standard_Real U2,
					     const Standard_Real V2) { 

  GeomAbs_SurfaceType SurfaceType = TheSurfaceTool::GetType(surface);
  switch(SurfaceType) { 
  case GeomAbs_Plane: 
    {
      IntAna_IntConicQuad EllipsePlane(Ellipse,TheSurfaceTool::Plane(surface),TOLERANCE_ANGULAIRE,TOLERANCE);
      AppendIntAna(curve,surface,EllipsePlane);
      break;
    }
  case GeomAbs_Cylinder:
    {
      IntAna_IntConicQuad EllipseCylinder(Ellipse,TheSurfaceTool::Cylinder(surface));
      AppendIntAna(curve,surface,EllipseCylinder);
      break;
    }
  case GeomAbs_Cone:
     {
      IntAna_IntConicQuad EllipseCone(Ellipse,TheSurfaceTool::Cone(surface));
      AppendIntAna(curve,surface,EllipseCone);
      break;
    }   
  case GeomAbs_Sphere:
    {
      IntAna_IntConicQuad EllipseSphere(Ellipse,TheSurfaceTool::Sphere(surface));
      AppendIntAna(curve,surface,EllipseSphere);
      break;
    }
  default: 
    {
      IntCurveSurface_ThePolygon polygon(curve,NBSAMPLESONELLIPSE);
      InternalPerform(curve,polygon,surface,U1,V1,U2,V2);
    }
  }
}
//=======================================================================
//function : PerformConicSurf
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::PerformConicSurf(const gp_Parab&       Parab,
					     const TheCurve&       curve,
					     const TheSurface&     surface,
					     const Standard_Real U1,
					     const Standard_Real V1,
					     const Standard_Real U2,
					     const Standard_Real V2) { 

  GeomAbs_SurfaceType SurfaceType = TheSurfaceTool::GetType(surface);
  switch(SurfaceType) { 
  case GeomAbs_Plane: 
    {
      IntAna_IntConicQuad ParabPlane(Parab,TheSurfaceTool::Plane(surface),TOLERANCE_ANGULAIRE);
      AppendIntAna(curve,surface,ParabPlane);
      break;
    }
  case GeomAbs_Cylinder:
    {
      IntAna_IntConicQuad ParabCylinder(Parab,TheSurfaceTool::Cylinder(surface));
      AppendIntAna(curve,surface,ParabCylinder);
      break;
    }
  case GeomAbs_Cone:
     {
      IntAna_IntConicQuad ParabCone(Parab,TheSurfaceTool::Cone(surface));
      AppendIntAna(curve,surface,ParabCone);
      break;
    }   
  case GeomAbs_Sphere:
    {
      IntAna_IntConicQuad ParabSphere(Parab,TheSurfaceTool::Sphere(surface));
      AppendIntAna(curve,surface,ParabSphere);
      break;
    }
  default: 
    {
      Standard_Integer nbsu,nbsv;
      nbsu = TheSurfaceTool::NbSamplesU(surface,U1,U2);
      nbsv = TheSurfaceTool::NbSamplesV(surface,V1,V2);
      if(nbsu>40) nbsu=40;
      if(nbsv>40) nbsv=40;
      IntCurveSurface_ThePolyhedron polyhedron(surface,nbsu,nbsv,U1,V1,U2,V2);
      Intf_Tool                         bndTool;
      Bnd_Box                          boxParab;
      bndTool.ParabBox(Parab,polyhedron.Bounding(),boxParab);
      for(Standard_Integer nbseg=1; nbseg<= bndTool.NbSegments(); nbseg++) { 
	IntCurveSurface_ThePolygon polygon(curve,
					   bndTool.BeginParam(nbseg),
					   bndTool.EndParam(nbseg),
					   NBSAMPLESONPARAB);
	InternalPerform(curve,polygon,surface,polyhedron,U1,V1,U2,V2);
      }
    }
  }
}
//=======================================================================
//function : PerformConicSurf
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::PerformConicSurf(const gp_Hypr&        Hypr,
					     const TheCurve&       curve,
					     const TheSurface&     surface,
					     const Standard_Real U1,
					     const Standard_Real V1,
					     const Standard_Real U2,
					     const Standard_Real V2) {
 
  GeomAbs_SurfaceType SurfaceType = TheSurfaceTool::GetType(surface);
  switch(SurfaceType) { 
  case GeomAbs_Plane: 
    {
      IntAna_IntConicQuad HyprPlane(Hypr,TheSurfaceTool::Plane(surface),TOLERANCE_ANGULAIRE);
      AppendIntAna(curve,surface,HyprPlane);
      break;
    }
  case GeomAbs_Cylinder:
    {
      IntAna_IntConicQuad HyprCylinder(Hypr,TheSurfaceTool::Cylinder(surface));
      AppendIntAna(curve,surface,HyprCylinder);
      break;
    }
  case GeomAbs_Cone:
     {
      IntAna_IntConicQuad HyprCone(Hypr,TheSurfaceTool::Cone(surface));
      AppendIntAna(curve,surface,HyprCone);
      break;
    }   
  case GeomAbs_Sphere:
    {
      IntAna_IntConicQuad HyprSphere(Hypr,TheSurfaceTool::Sphere(surface));
      AppendIntAna(curve,surface,HyprSphere);
      break;
    }
  default: 
    {
      Standard_Integer nbsu,nbsv;
      nbsu = TheSurfaceTool::NbSamplesU(surface,U1,U2);
      nbsv = TheSurfaceTool::NbSamplesV(surface,V1,V2);
      if(nbsu>40) nbsu=40;
      if(nbsv>40) nbsv=40;
      IntCurveSurface_ThePolyhedron polyhedron(surface,nbsu,nbsv,U1,V1,U2,V2);
      Intf_Tool                         bndTool;
      Bnd_Box                          boxHypr;
      bndTool.HyprBox(Hypr,polyhedron.Bounding(),boxHypr);
      for(Standard_Integer nbseg=1; nbseg<= bndTool.NbSegments(); nbseg++) { 
	IntCurveSurface_ThePolygon polygon(curve,
					   bndTool.BeginParam(nbseg),
					   bndTool.EndParam(nbseg),
					   NBSAMPLESONHYPR);
	InternalPerform(curve,polygon,surface,polyhedron,U1,V1,U2,V2);
      }
    }
  }
}
//=======================================================================
//function : AppendIntAna
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::AppendIntAna(const TheCurve& curve,
					 const TheSurface& surface,
					 const IntAna_IntConicQuad& intana_ConicQuad) {
  if(intana_ConicQuad.IsDone()) { 
    if(intana_ConicQuad.IsInQuadric()) { 
      //-- std::cout<<" Courbe Dans la Quadrique !!! Non Traite !!!"<<std::endl;
      myIsParallel = Standard_True;
    }
    else if(intana_ConicQuad.IsParallel()) { 
      //-- std::cout<<" Courbe // a la Quadrique !!! Non Traite !!!"<<std::endl;
      myIsParallel = Standard_True;
    }
    else { 
      Standard_Integer nbp = intana_ConicQuad.NbPoints();
      Standard_Real u,v,w;
      for(Standard_Integer i = 1; i<= nbp; i++) { 
	gp_Pnt P(intana_ConicQuad.Point(i));
	w = intana_ConicQuad.ParamOnConic(i);
	IntCurveSurface_ComputeParamsOnQuadric(surface,P,u,v);
	AppendPoint(curve,w,surface,u,v);
      }
    }
  }
  else { 
    //-- std::cout<<" IntAna Conic Quad Not Done  "<<std::endl;
  }
}
//=======================================================================
//function : AppendPoint
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::AppendPoint(const TheCurve& curve,
					const Standard_Real lw,
					const TheSurface& surface,
					const Standard_Real su,
					const Standard_Real sv) {
 
  Standard_Real W0 = TheCurveTool::FirstParameter(curve);
  Standard_Real W1 = TheCurveTool::LastParameter(curve);
  Standard_Real U0 = TheSurfaceTool::FirstUParameter(surface);
  Standard_Real U1 = TheSurfaceTool::LastUParameter(surface);
  Standard_Real V0 = TheSurfaceTool::FirstVParameter(surface);
  Standard_Real V1 = TheSurfaceTool::LastVParameter(surface);
  //-- Test si la courbe est periodique
  Standard_Real w = lw, u = su, v = sv;

  GeomAbs_CurveType aCType = TheCurveTool::GetType(curve);

  if(TheCurveTool::IsPeriodic(curve) 
     || aCType == GeomAbs_Circle 
     || aCType == GeomAbs_Ellipse) {
    w = ElCLib::InPeriod(w, W0, W0 + TheCurveTool::Period(curve));
  }

  if((W0 - w) >= TOLTANGENCY || (w - W1) >= TOLTANGENCY) return;

  GeomAbs_SurfaceType aSType = TheSurfaceTool::GetType(surface);
  if (TheSurfaceTool::IsUPeriodic(surface)
      || aSType == GeomAbs_Cylinder
      || aSType == GeomAbs_Cone
      || aSType == GeomAbs_Sphere) {
    u = ElCLib::InPeriod(u, U0, U0 + TheSurfaceTool::UPeriod(surface));
  }

  if (TheSurfaceTool::IsVPeriodic(surface)) {
    v = ElCLib::InPeriod(v, V0, V0 + TheSurfaceTool::VPeriod(surface));
  }

  if((U0 - u) >= TOLTANGENCY || (u - U1) >= TOLTANGENCY) return;
  if((V0 - v) >= TOLTANGENCY || (v - V1) >= TOLTANGENCY) return;

  IntCurveSurface_TransitionOnCurve   TransOnCurve;
  IntCurveSurface_ComputeTransitions(curve,w,TransOnCurve,
				     surface,u,v);
  gp_Pnt P(TheCurveTool::Value(curve,w));
  IntCurveSurface_IntersectionPoint IP(P,u,v,w,TransOnCurve);
  Append(IP); //-- invoque la methode de IntCurveSurface_Intersection.
  
}

//=======================================================================
//function : AppendSegment
//purpose  : 
//=======================================================================
void IntCurveSurface_Inter::AppendSegment(const TheCurve& ,
					  const Standard_Real ,
					  const Standard_Real ,
					  const TheSurface& ) { 
  //std::cout<<" !!! Not Yet Implemented 
  //IntCurveSurface_Inter::Append(const IntCurveSurf ...)"<<std::endl;
}

//=======================================================================
//function : SectionPointToParameters
//purpose  : P o i n t   d   i n t e r f e r e n c e   - - >  
//    U , V       e t   W 
//=======================================================================
void SectionPointToParameters(const Intf_SectionPoint&              Sp,
			      const IntCurveSurface_ThePolyhedron&  Polyhedron,
			      const IntCurveSurface_ThePolygon&     Polygon,
			      Standard_Real& U,
			      Standard_Real& V,
			      Standard_Real& W) {
  
  Intf_PIType       typ;
  Standard_Integer  Adr1,Adr2;
  Standard_Real     Param,u,v;
  gp_Pnt P(Sp.Pnt());
  
  Standard_Integer Pt1,Pt2,Pt3;
  Standard_Real u1 = 0.,v1 = 0.,param;
  //----------------------------------------------------------------------
  //--          Calcul des parametres approches sur la surface          --
  //----------------------------------------------------------------------
  
  Sp.InfoSecond(typ,Adr1,Adr2,Param);
  switch(typ) { 
  case Intf_VERTEX:   //-- Adr1 est le numero du vertex
    {
      Polyhedron.Parameters(Adr1,u1,v1);
      break;
    }
  case Intf_EDGE:
    {
      Polyhedron.Parameters(Adr1,u1,v1);    
      Polyhedron.Parameters(Adr2,u,v);
      u1+= Param * (u-u1);
      v1+= Param * (v-v1);
      break;
    }
  case Intf_FACE:
    {
      Standard_Real ua,va,ub,vb,uc,vc,ca,cb,cc,cabc;
      Polyhedron.Triangle(Adr1,Pt1,Pt2,Pt3);
      gp_Pnt PA(Polyhedron.Point(Pt1));
      gp_Pnt PB(Polyhedron.Point(Pt2));
      gp_Pnt PC(Polyhedron.Point(Pt3));
      Polyhedron.Parameters(Pt1,ua,va);
      Polyhedron.Parameters(Pt2,ub,vb);
      Polyhedron.Parameters(Pt3,uc,vc);
      gp_Vec Normale(gp_Vec(PA,PB).Crossed(gp_Vec(PA,PC)));
      cc = (gp_Vec(PA,PB).Crossed(gp_Vec(PA,P))).Dot(Normale);
      ca = (gp_Vec(PB,PC).Crossed(gp_Vec(PB,P))).Dot(Normale);
      cb = (gp_Vec(PC,PA).Crossed(gp_Vec(PC,P))).Dot(Normale);
      cabc = ca + cb + cc;
      
      ca/=cabc;     cb/=cabc;       cc/=cabc;
      
      u1 = ca * ua + cb * ub + cc * uc;
      v1 = ca * va + cb * vb + cc * vc;
      break;
    }
  default: 
    {
      std::cout<<" Default dans SectionPointToParameters "<<std::endl;
      break;
    }
  }
  //----------------------------------------------------------------------
  //--                Calcul du point approche sur la Curve             --
  //----------------------------------------------------------------------
  Standard_Integer SegIndex;

  Sp.InfoFirst(typ,SegIndex,param);
  W = Polygon.ApproxParamOnCurve(SegIndex,param);
  if(param>1.0 || param<0.0) { 
    //-- IntCurveSurface_ThePolyhedronTool::Dump(Polyhedron);
    //-- IntCurveSurface_ThePolygonTool::Dump(Polygon);
    }
  U = u1;
  V = v1;
}
//=======================================================================
//function : IntCurveSurface_ComputeTransitions
//purpose  : 
//=======================================================================
void IntCurveSurface_ComputeTransitions(const TheCurve& curve,
					const Standard_Real w,
					IntCurveSurface_TransitionOnCurve&   TransOnCurve,
					const TheSurface& surface,
					const Standard_Real u,
					const Standard_Real v) { 
  
  gp_Vec NSurf,D1U,D1V;//TgCurv;
  gp_Pnt Psurf;
  Standard_Real CosDir;
  
  
  TheSurfaceTool::D1(surface,u,v,Psurf,D1U,D1V);
  NSurf = D1U.Crossed(D1V);
  TheCurveTool::D1(curve,w,Psurf,D1U);
  Standard_Real Norm = NSurf.Magnitude();
  if(Norm>TOLERANCE_ANGULAIRE &&
     D1U.SquareMagnitude() > TOLERANCE_ANGULAIRE) { 
    D1U.Normalize();
    CosDir = NSurf.Dot(D1U);
    CosDir/=Norm;
    if( -CosDir > TOLERANCE_ANGULAIRE) { 
      //--  --Curve--->    <----Surface----
      TransOnCurve   = IntCurveSurface_In;
    }
    else if(CosDir > TOLERANCE_ANGULAIRE) { 
      //--  --Curve--->  ----Surface-->
      TransOnCurve   = IntCurveSurface_Out;
    }	  
    else { 
      TransOnCurve   = IntCurveSurface_Tangent;
    }
  }
  else { 
    TransOnCurve   = IntCurveSurface_Tangent;
  }
}
//=======================================================================
//function : IntCurveSurface_ComputeParamsOnQuadric
//purpose  : 
//=======================================================================
void IntCurveSurface_ComputeParamsOnQuadric(const TheSurface& surface,
					    const gp_Pnt& P,
					    Standard_Real& u,
					    Standard_Real& v) { 
  GeomAbs_SurfaceType SurfaceType = TheSurfaceTool::GetType(surface);
  switch(SurfaceType) { 
  case GeomAbs_Plane: 
    {
      ElSLib::Parameters(TheSurfaceTool::Plane(surface),P,u,v);
	break;
      }
  case GeomAbs_Cylinder:
    {
      ElSLib::Parameters(TheSurfaceTool::Cylinder(surface),P,u,v);
	break;
      }
  case GeomAbs_Cone:
    {
      ElSLib::Parameters(TheSurfaceTool::Cone(surface),P,u,v);
	break;
      }   
  case GeomAbs_Sphere:
    {
      ElSLib::Parameters(TheSurfaceTool::Sphere(surface),P,u,v);
	break;
      }
  default:
    break;
  }
}
//=======================================================================
//function : EstLimForInfExtr
//purpose  : Estimation of limits for infinite surfaces
//=======================================================================
void EstLimForInfExtr(const gp_Lin&   Line,
		      const TheSurface& surface, 
		      const Standard_Boolean IsOffSurf,
		      const Standard_Integer nbsu, 
		      const Standard_Boolean U1inf, 
		      const Standard_Boolean U2inf, 
		      const Standard_Boolean V1inf, 
		      const Standard_Boolean V2inf, 
		      Standard_Real& U1new, 
		      Standard_Real& U2new, 
		      Standard_Real& V1new, 
		      Standard_Real& V2new, 
		      Standard_Boolean& NoIntersection)

{

  NoIntersection = Standard_False;

  Handle(Adaptor3d_Surface) aBasSurf; 

  if(IsOffSurf) aBasSurf = TheSurfaceTool::BasisSurface(surface);

  gp_Dir aDirOfExt;

  if(IsOffSurf) aDirOfExt = aBasSurf->Direction();
  else aDirOfExt = TheSurfaceTool::Direction(surface);

  Standard_Real tolang = TOLERANCE_ANGULAIRE;

  if(aDirOfExt.IsParallel(Line.Direction(), tolang)) {
    NoIntersection = Standard_True;
    return;
  }

  if((V1inf || V2inf) && !(U1inf || U2inf)) {

    Standard_Real vmin = RealLast(), vmax = -vmin;
    gp_Lin aL;
    Standard_Real step = (U2new - U1new) / nbsu;
    Standard_Real u = U1new, v;
    gp_Pnt aP;
    Extrema_POnCurv aP1, aP2;
    Standard_Integer i;

    for(i = 0; i <= nbsu; i++) {

      TheSurfaceTool::D0(surface, u, 0., aP);
      aL.SetLocation(aP);
      aL.SetDirection(aDirOfExt);

      Extrema_ExtElC aExtr(aL, Line, tolang);
      
      if(!aExtr.IsDone()) return;

      if(aExtr.IsParallel()) {
	NoIntersection = Standard_True;
	return;
      }

      aExtr.Points(1, aP1, aP2);
      v = aP1.Parameter();
      vmin = Min(vmin, v);
      vmax = Max(vmax, v);

      u += step;

    }

    vmin = vmin - Abs(vmin) - 10.;
    vmax = vmax + Abs(vmax) + 10.;

    V1new = Max(V1new, vmin);
    V2new = Min(V2new, vmax);

  }
  else if(U1inf || U2inf) {

    Standard_Real umin = RealLast(), umax = -umin;
    Standard_Real u0 = Min(Max(0., U1new), U2new);
    Standard_Real v0 = Min(Max(0., V1new), V2new);
    gp_Pnt aP;
    TheSurfaceTool::D0(surface, u0, v0, aP);
    gp_Pln aRefPln(aP, aDirOfExt);

    Handle(Adaptor3d_Curve) aBasCurv;

    if(IsOffSurf) aBasCurv = aBasSurf->BasisCurve();
    else aBasCurv = TheSurfaceTool::BasisCurve(surface);

    ProjLib_Plane Projector(aRefPln);

    Projector.Project(Line);

    if(!Projector.IsDone()) return;

    gp_Lin2d Line2d = Projector.Line();

    GeomAbs_CurveType aCurvTyp = aBasCurv->GetType();

    if(aCurvTyp == GeomAbs_Line) {
      
      Projector.Project(aBasCurv->Line());

      if(!Projector.IsDone()) return;

      gp_Lin2d aL2d = Projector.Line();

      IntAna2d_AnaIntersection anInter(Line2d, aL2d);

      if(!anInter.IsDone()) return;

      if(anInter.IsEmpty() || anInter.IdenticalElements() || 
	                      anInter.ParallelElements()     ) {
	NoIntersection = Standard_True;
	return;
      }

      const IntAna2d_IntPoint& anIntPnt = anInter.Point(1);
      umin = umax = anIntPnt.ParamOnSecond();
    }
    else if(aCurvTyp == GeomAbs_Parabola || aCurvTyp == GeomAbs_Hyperbola) {

      IntAna2d_Conic aCon(Line2d);
      IntAna2d_AnaIntersection anInter;
      
      if(aCurvTyp == GeomAbs_Parabola) {
	Projector.Project(aBasCurv->Parabola());
	if(!Projector.IsDone()) return;

	const gp_Parab2d& aP2d = Projector.Parabola();

	anInter.Perform(aP2d, aCon);
      }
      else {
	Projector.Project(aBasCurv->Hyperbola());
	if(!Projector.IsDone()) return;

	const gp_Hypr2d& aH2d = Projector.Hyperbola();
	anInter.Perform(aH2d, aCon);
      }

      if(!anInter.IsDone()) return;

      if(anInter.IsEmpty()) {
	NoIntersection = Standard_True;
	return;
      }

      Standard_Integer i, nbint = anInter.NbPoints();
      for(i = 1; i <= nbint; i++) {

	const IntAna2d_IntPoint& anIntPnt = anInter.Point(i);

	umin = Min(anIntPnt.ParamOnFirst(), umin);
	umax = Max(anIntPnt.ParamOnFirst(), umax);
 
      }

    }
    else {
      return;
    }
      
    umin = umin - Abs(umin) - 10;
    umax = umax + Abs(umax) + 10;

    U1new = Max(U1new, umin);
    U2new = Min(U2new, umax);
    
    if(V1inf || V2inf) {
      EstLimForInfExtr(Line, surface, IsOffSurf, nbsu, 
		       Standard_False, Standard_False, V1inf, V2inf,
		       U1new, U2new, V1new, V2new, NoIntersection);
    }
  }
    
  return;
  
}
//=======================================================================
//function : ProjectIntersectAndEstLim
//purpose  : project <theLine> and it's X-axe symmetric line to <thePln> and
//           intersect resulting curve with <theBasCurvProj>.
//           Then estimate max and min parameters of intersection on
//           <theBasCurvProj>.
//           Is called from EstLimForInfRevl()
//=======================================================================
void ProjectIntersectAndEstLim(const gp_Lin&        theLine,
			       const gp_Pln&        thePln,
			       const ProjLib_Plane& theBasCurvProj,
			       Standard_Real&       theVmin,
			       Standard_Real&       theVmax,
			       Standard_Boolean&    theNoIntersection)
{
  ProjLib_Plane aLineProj( thePln, theLine );
  if (!aLineProj.IsDone()) {
#ifdef OCCT_DEBUG
  std::cout
  << "Info: IntCurveSurface_Inter::ProjectIntersectAndEstLim(), !aLineProj.IsDone()"
  << std::endl;
#endif
    return;
  }
  gp_Lin2d aLin2d = aLineProj.Line();

  // make a second line X-axe symmetric to the first one 
  gp_Pnt2d aP1 = aLin2d.Location();
  gp_Pnt2d aP2 (aP1.XY() + aLin2d.Direction().XY());
  gp_Pnt2d aP1sym (aP1.X(), -aP1.Y());
  gp_Pnt2d aP2sym (aP2.X(), -aP2.Y());
  gp_Lin2d aLin2dsym (aP1sym, gp_Vec2d(aP1sym,aP2sym));
  
  // intersect projections
  IntAna2d_Conic aCon    (aLin2d);
  IntAna2d_Conic aConSym (aLin2dsym);
  IntAna2d_AnaIntersection anIntersect;
  IntAna2d_AnaIntersection anIntersectSym;
  
  switch (theBasCurvProj.GetType()) {
  case GeomAbs_Line:
    anIntersectSym.Perform(theBasCurvProj.Line(), aConSym); 
    anIntersect.Perform(theBasCurvProj.Line(), aCon); break;
  case GeomAbs_Hyperbola:			  
    anIntersectSym.Perform(theBasCurvProj.Hyperbola(), aConSym); 
    anIntersect.Perform(theBasCurvProj.Hyperbola(), aCon); break;
  case GeomAbs_Parabola:			  
    anIntersectSym.Perform(theBasCurvProj.Parabola(), aConSym); 
    anIntersect.Perform(theBasCurvProj.Parabola(), aCon); break;
  default:
    return; // not infinite curve
  }

  // retrieve params of intersections
  Standard_Integer aNbIntPnt = anIntersect.IsDone() ? anIntersect.NbPoints() : 0;
  Standard_Integer aNbIntPntSym = anIntersectSym.IsDone() ? anIntersectSym.NbPoints() : 0;
  Standard_Integer iPnt, aNbPnt = Max (aNbIntPnt, aNbIntPntSym);
  
  if (aNbPnt == 0) {
    theNoIntersection = Standard_True;
    return;
  }
  Standard_Real aParam;
  for (iPnt = 1; iPnt <= aNbPnt; iPnt++)
  {
    if (iPnt <= aNbIntPnt) {
      const IntAna2d_IntPoint& aIntPnt = anIntersect.Point(iPnt);
      aParam = aIntPnt.ParamOnFirst();
      theVmin = Min (theVmin, aParam );
      theVmax = Max (theVmax, aParam );
    }
    if (iPnt <= aNbIntPntSym) {
      const IntAna2d_IntPoint& aIntPnt = anIntersectSym.Point(iPnt);
      aParam = aIntPnt.ParamOnFirst();
      theVmin = Min (theVmin, aParam );
      theVmax = Max (theVmax, aParam );
    }
  }

  return;
}
//=======================================================================
//function : EstLimForInfRevl
//purpose  : Estimate V1 and V2 to pass to InternalPerform() if they are
//           infinite for Surface of Revolution
//           Algo: intersect projections of Line and basis curve on the
//           plane passing through revolution axe
//=======================================================================
void EstLimForInfRevl(const gp_Lin&   Line,
		      const TheSurface& surface, 
		      const Standard_Boolean U1inf, 
		      const Standard_Boolean U2inf, 
		      const Standard_Boolean V1inf, 
		      const Standard_Boolean V2inf, 
		      Standard_Real& U1new, 
		      Standard_Real& U2new, 
		      Standard_Real& V1new, 
		      Standard_Real& V2new, 
		      Standard_Boolean& NoIntersection)
{

  NoIntersection = Standard_False;

  if (U1inf || U2inf) {
    if (U1inf)
      U1new = Max (0., U1new);
    else
      U2new = Min (2 * M_PI, U2new);
    if (! V1inf && !V2inf) return;
  }

  Handle(Adaptor3d_Curve) aBasisCurve = TheSurfaceTool::BasisCurve(surface);
  gp_Ax1 aRevAx = TheSurfaceTool::AxeOfRevolution(surface);
  gp_Vec aXVec = aRevAx.Direction();
  Standard_Real aTolAng = Precision::Angular();

  // make plane to project a basis curve
  gp_Pnt O = aRevAx.Location();
  Standard_Real aU = 0.;
  gp_Pnt P = aBasisCurve->Value(aU);
  while (O.SquareDistance(P) <= Precision::PConfusion() ||
	 aXVec.IsParallel( gp_Vec(O,P), aTolAng)) {
    aU += 1.;
    P = aBasisCurve->Value(aU);
    if (aU > 3)
      // basis curve is a line coinciding with aXVec, P is any not on aXVec
      P = gp_Pnt(aU, aU+1, aU+2);
  }
  gp_Vec aNVec = aXVec ^ gp_Vec(O,P);
  gp_Pln aPln (gp_Ax3 (O, aNVec ,aXVec));

  // project basic curve
  ProjLib_Plane aBasCurvProj(aPln);
  switch (aBasisCurve->GetType()) {
  case GeomAbs_Line:
    aBasCurvProj.Project(aBasisCurve->Line     ()); break;
  case GeomAbs_Hyperbola:			
    aBasCurvProj.Project(aBasisCurve->Hyperbola()); break;
  case GeomAbs_Parabola:			
    aBasCurvProj.Project(aBasisCurve->Parabola ()); break;
  default:
    return; // not infinite curve
  }
  if (!aBasCurvProj.IsDone()) {
#ifdef OCCT_DEBUG
    std::cout << "Info: IntCurveSurface_Inter::EstLimForInfRevl(), !aBasCurvProj.IsDone()" << std::endl;
#endif
    return;
  }
  // make plane to project Line
  if (aXVec.IsParallel( Line.Direction(), aTolAng)) {
    P = Line.Location();
    while (O.SquareDistance(P) <= Precision::PConfusion()) {
      aU += 1.;
      P = gp_Pnt(aU, aU+1, aU+2); // any not on aXVec
    }
    aNVec = aXVec ^ gp_Vec(O,P);
  } else
    aNVec = aXVec.Crossed( Line.Direction() );
  
  aPln  = gp_Pln (gp_Ax3 (O, aNVec ,aXVec));

  // make a second plane perpendicular to the first one, rotated around aXVec
  gp_Pln aPlnPrp = aPln.Rotated (gp_Ax1 (O,aXVec), M_PI/2.);
  
  // project Line and it's X-axe symmetric one to plane and intersect
  // resulting curve with projection of Basic Curev
  Standard_Real aVmin = RealLast(), aVmax = -aVmin;
  Standard_Boolean aNoInt1 = Standard_False, aNoInt2 = Standard_False;
  ProjectIntersectAndEstLim (Line, aPln,    aBasCurvProj, aVmin, aVmax, aNoInt1);
  ProjectIntersectAndEstLim (Line, aPlnPrp, aBasCurvProj, aVmin, aVmax, aNoInt2);

  if (aNoInt1 && aNoInt2) {
    NoIntersection = Standard_True;
    return;
  }
  
  aVmin = aVmin - Abs(aVmin) - 10;
  aVmax = aVmax + Abs(aVmax) + 10;

  if (V1inf) V1new = aVmin;
  if (V2inf) V2new = aVmax;

  //std::cout << "EstLimForInfRevl: Vmin " << V1new << " Vmax " << V2new << std::endl;
  
  return;
}

//=======================================================================
//function : EstLimForInfOffs
//purpose  : 
//=======================================================================
void EstLimForInfOffs(const gp_Lin&   Line,
		      const TheSurface& surface, 
		      const Standard_Integer nbsu, 
		      const Standard_Boolean U1inf, 
		      const Standard_Boolean U2inf, 
		      const Standard_Boolean V1inf, 
		      const Standard_Boolean V2inf, 
		      Standard_Real& U1new, 
		      Standard_Real& U2new, 
		      Standard_Real& V1new, 
		      Standard_Real& V2new, 
		      Standard_Boolean& NoIntersection)
{

  NoIntersection = Standard_False;

  const Handle(Adaptor3d_Surface)& aBasSurf = TheSurfaceTool::BasisSurface(surface);
  Standard_Real anOffVal = TheSurfaceTool::OffsetValue(surface);

  GeomAbs_SurfaceType aTypeOfBasSurf = aBasSurf->GetType();

  //  case for plane, cylinder and cone - make equivalent surface;
  if(aTypeOfBasSurf == GeomAbs_Plane) {

    gp_Pln aPln = aBasSurf->Plane();
    gp_Vec aT = aPln.Position().XDirection()^aPln.Position().YDirection();
    aT *= anOffVal;
    aPln.Translate(aT);
    IntAna_IntConicQuad LinPlane(Line,aPln,TOLERANCE_ANGULAIRE);

    if(!LinPlane.IsDone()) return;

    if(LinPlane.IsParallel() || LinPlane.IsInQuadric()) {

      NoIntersection = Standard_True;
      return;

    }
    
    Standard_Real u, v;
    ElSLib::Parameters(aPln, LinPlane.Point(1), u, v);
    U1new = Max(U1new, u - 10.);
    U2new = Min(U2new, u + 10.);
    V1new = Max(V1new, v - 10.);
    V2new = Min(V2new, v + 10.);

  }
  else if(aTypeOfBasSurf == GeomAbs_Cylinder) {

    gp_Cylinder aCyl = aBasSurf->Cylinder();

    Standard_Real aR = aCyl.Radius();
    gp_Ax3 anA = aCyl.Position();

    if (anA.Direct()) 
      aR += anOffVal;
    else 
      aR -= anOffVal;

    if ( aR >= TOLTANGENCY ) {
      aCyl.SetRadius(aR);
    }
    else if ( aR <= -TOLTANGENCY ){
      anA.Rotate(gp_Ax1(anA.Location(), anA.Direction()), M_PI);
      aCyl.SetPosition(anA);
// modified by NIZHNY-MKK  Mon Oct  3 17:37:54 2005
//       aCyl.SetRadius(Abs(aR));
      aCyl.SetRadius(-aR);
    }
    else {

      NoIntersection = Standard_True;
      return;
      
    }

    IntAna_IntConicQuad LinCylinder(Line, aCyl);

    if(!LinCylinder.IsDone()) return;

    if(LinCylinder.IsParallel() || LinCylinder.IsInQuadric()) {

      NoIntersection = Standard_True;
      return;

    }
    
    Standard_Integer i, nbp = LinCylinder.NbPoints();
    Standard_Real vmin = RealLast(), vmax = -vmin, u, v;

    for(i = 1; i <= nbp; i++) {

      ElSLib::Parameters(aCyl, LinCylinder.Point(i), u, v);
      vmin = Min(vmin, v);
      vmax = Max(vmax, v);

    } 

    V1new = Max(V1new, vmin - Abs(vmin) - 10.);
    V2new = Min(V2new, vmax + Abs(vmax) + 10.);

  }
  else if(aTypeOfBasSurf == GeomAbs_Cone) {

    gp_Cone aCon = aBasSurf->Cone();
    Standard_Real anAng = aCon.SemiAngle();
    Standard_Real aR = aCon.RefRadius() + anOffVal * Cos(anAng);
    gp_Ax3 anA = aCon.Position();
    if ( aR >= 0.) {

      gp_Vec aZ( anA.Direction());
      aZ *= - anOffVal * Sin(anAng);
      anA.Translate(aZ);
      aCon.SetPosition(anA);
      aCon.SetRadius(aR);
      aCon.SetSemiAngle(anAng);

    }
    else {

      return;

    }

    IntAna_IntConicQuad LinCone(Line, aCon);

    if(!LinCone.IsDone()) return;

    if(LinCone.IsParallel() || LinCone.IsInQuadric()) {

      NoIntersection = Standard_True;
      return;

    }
    
    Standard_Integer i, nbp = LinCone.NbPoints();
    Standard_Real vmin = RealLast(), vmax = -vmin, u, v;

    for(i = 1; i <= nbp; i++) {

      ElSLib::Parameters(aCon, LinCone.Point(i), u, v);
      vmin = Min(vmin, v);
      vmax = Max(vmax, v);

    } 

    V1new = Max(V1new, vmin - Abs(vmin) - 10.);
    V2new = Min(V2new, vmax + Abs(vmax) + 10.);

  }
  else if(aTypeOfBasSurf == GeomAbs_SurfaceOfExtrusion) {

    Standard_Real anU1 = U1new, anU2 = U2new;

    EstLimForInfExtr(Line, surface, Standard_True, nbsu, 
		     U1inf, U2inf, V1inf, V2inf, 
		     U1new, U2new, V1new, V2new, NoIntersection);

    if(NoIntersection) return;

    if(U1inf || U2inf) {

      GeomAbs_CurveType aBasCurvType = aBasSurf->BasisCurve()->GetType();
      if(aBasCurvType == GeomAbs_Line) {
	U1new = Max(anU1, -1.e10);
	U2new = Min(anU2,  1.e10);
      }	
      else if(aBasCurvType == GeomAbs_Parabola) {
	gp_Parab aPrb  = aBasSurf->BasisCurve()->Parabola();
	Standard_Real aF = aPrb.Focal();
	Standard_Real dU = 2.e5 * Sqrt(aF);
	U1new = Max(anU1, -dU);
	U2new = Min(anU2,  dU);
      }
      else if(aBasCurvType == GeomAbs_Hyperbola) {
	U1new = Max(anU1, -30.);
	U2new = Min(anU2,  30.);
      }
      else {
	U1new = Max(anU1, -1.e10);
	U2new = Min(anU2,  1.e10);
      }	

    }

  }
  else if(aTypeOfBasSurf == GeomAbs_SurfaceOfRevolution) {

    GeomAbs_CurveType aBasCurvType = aBasSurf->BasisCurve()->GetType();
    if(aBasCurvType == GeomAbs_Line) {
      V1new = Max(V1new, -1.e10);
      V2new = Min(V2new,  1.e10);
    }	
    else if(aBasCurvType == GeomAbs_Parabola) {
      gp_Parab aPrb  = aBasSurf->BasisCurve()->Parabola();
      Standard_Real aF = aPrb.Focal();
      Standard_Real dV = 2.e5 * Sqrt(aF);
      V1new = Max(V1new, -dV);
      V2new = Min(V2new,  dV);
    }
    else if(aBasCurvType == GeomAbs_Hyperbola) {
     V1new  = Max(V1new, -30.);
     V2new  = Min(V2new,  30.);
    }
    else {
     V1new  = Max(V1new, -1.e10);
     V2new  = Min(V2new,  1.e10);
    }	

  }
  else {

    V1new = Max(V1new, -1.e10);
    V2new = Min(V2new,  1.e10);
  }
}
//=======================================================================
//function : EstLimForInfSurf
//purpose  : 
//=======================================================================
void EstLimForInfSurf(Standard_Real& U1new, 
		      Standard_Real& U2new, 
		      Standard_Real& V1new, 
		      Standard_Real& V2new)
{
    U1new = Max(U1new, -1.e10);
    U2new = Min(U2new,  1.e10);
    V1new = Max(V1new, -1.e10);
    V2new = Min(V2new,  1.e10);
}
