// Created on: 1992-10-13
// Created by: Laurent BUCHARD
// Copyright (c) 1992-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.

//  Modified by skv - Tue Mar  1 14:22:09 2005 OCC8169


#ifndef OCCT_DEBUG
#define No_Standard_RangeError
#define No_Standard_OutOfRange
#endif


#include <Standard_ConstructionError.hxx>

#include <IntRes2d_Domain.hxx>
#include <IntRes2d_Position.hxx>
#include <IntRes2d_Transition.hxx>
#include <IntRes2d_IntersectionPoint.hxx>
#include <IntRes2d_IntersectionSegment.hxx>


#include <IntImpParGen.hxx>

#include <Intf_SectionPoint.hxx>
#include <Intf_SectionLine.hxx>
#include <Intf_TangentZone.hxx>
#include <Intf_InterferencePolygon2d.hxx>

#include <gp_Vec2d.hxx>

#include <math_Vector.hxx>
#include <math_FunctionSetRoot.hxx>
#include <math_NewtonFunctionSetRoot.hxx>
#include <NCollection_Handle.hxx>
#include <Bnd_Box2d.hxx>
#include <Precision.hxx>

//======================================================================

#define NBITER_MAX_POLYGON 10
#define TOL_CONF_MINI   0.0000000001
#define TOL_MINI        0.0000000001

//----------------------------------------------------------------------


void GetIntersection(const TheCurve& theC1, const Standard_Real theT1f, const Standard_Real theT1l,
                     const TheCurve& theC2, const Standard_Real theT2f, const Standard_Real theT2l, 
                     const Standard_Real theTolConf,
                     const Standard_Integer theMaxCount,
                     IntRes2d_IntersectionPoint& thePInt, Standard_Real& theDist,
                     Standard_Integer& theCount);


Standard_Boolean HeadOrEndPoint( const IntRes2d_Domain& D1
				,const TheCurve& C1
				,const Standard_Real u
				,const IntRes2d_Domain& D2
				,const TheCurve& C2
				,const Standard_Real v
				,const Standard_Real TolConf
				,IntRes2d_IntersectionPoint& IntPt
				,Standard_Boolean& HeadOn1
				,Standard_Boolean& HeadOn2
				,Standard_Boolean& EndOn1
				,Standard_Boolean& EndOn2
				,Standard_Integer  PosSegment);


//======================================================================
IntCurve_IntPolyPolyGen::IntCurve_IntPolyPolyGen()
{
  const Standard_Integer aMinPntNb = 20; // Minimum number of samples.
  myMinPntNb = aMinPntNb;
  done = Standard_False;
}
//======================================================================
void IntCurve_IntPolyPolyGen::Perform( const TheCurve& C1
				      ,const IntRes2d_Domain& D1
				      ,const TheCurve& C2
				      ,const IntRes2d_Domain& D2
				      ,const Standard_Real TheTolConf
				      ,const Standard_Real TheTol)
{
  this->ResetFields();
  DomainOnCurve1=D1;
  DomainOnCurve2=D2; 
  Standard_Real DU = D1.LastParameter()-D1.FirstParameter();
  Standard_Real DV = D2.LastParameter()-D2.FirstParameter();
  Standard_Real Tl=(TheTol < TOL_MINI)? TOL_MINI : TheTol;
  Standard_Real TlConf=(TheTolConf < TOL_CONF_MINI)? TOL_CONF_MINI : TheTolConf;
  Perform(C1,D1,C2,D2,TlConf,Tl,0,DU,DV);
  //----------------------------------------------------------------------
  //-- Processing of end points
  //----------------------------------------------------------------------
  Standard_Boolean HeadOn1 = Standard_False;
  Standard_Boolean HeadOn2 = Standard_False;
  Standard_Boolean EndOn1  = Standard_False;
  Standard_Boolean EndOn2  = Standard_False;
  Standard_Integer i;
  Standard_Integer n=this->NbPoints();


  //--------------------------------------------------------------------
  //-- The points Head Head ... End End are not rejected if
  //-- they are already present at the end of segment 
  //-- ( It is not possible to test the equities on the parameters)
  //-- ( these points are not found at EpsX precision    )
  //-- PosSegment =            1    if Head Head
  //--                       2      if Head End
  //--                     4        if End  Head
  //--                   8          if End  End
  //--------------------------------------------------------------------
  Standard_Integer PosSegment = 0;

  for(i=1;i<=n;i++) { 
    IntRes2d_Position Pos1 = this->Point(i).TransitionOfFirst().PositionOnCurve();
    if(Pos1 == IntRes2d_Head) HeadOn1 = Standard_True;
    else if(Pos1 == IntRes2d_End) EndOn1 = Standard_True;

    IntRes2d_Position Pos2 =  this->Point(i).TransitionOfSecond().PositionOnCurve();
    if(Pos2 == IntRes2d_Head) HeadOn2 = Standard_True;
    else if(Pos2 == IntRes2d_End) EndOn2 = Standard_True;

    if(Pos1 == IntRes2d_Head) { 
      if(Pos2 == IntRes2d_Head)     PosSegment|=1;
      else if(Pos2 == IntRes2d_End) PosSegment|=2;
    }
    else if(Pos1 == IntRes2d_End) { 
      if(Pos2 == IntRes2d_Head)     PosSegment|=4;
      else if(Pos2 == IntRes2d_End) PosSegment|=8;
    }
  }
  
  n=this->NbSegments();
  for(i=1;i<=n;i++) { 
    IntRes2d_Position Pos1 = this->Segment(i).FirstPoint().TransitionOfFirst().PositionOnCurve();
    if(Pos1 == IntRes2d_Head)     HeadOn1 = Standard_True;
    else if(Pos1 == IntRes2d_End) EndOn1  = Standard_True;
    
    IntRes2d_Position Pos2 =  this->Segment(i).FirstPoint().TransitionOfSecond().PositionOnCurve();
    if(Pos2 == IntRes2d_Head)      HeadOn2 = Standard_True;
    else if(Pos2 == IntRes2d_End)  EndOn2  = Standard_True;

    if(Pos1 == IntRes2d_Head) { 
      if(Pos2 == IntRes2d_Head)     PosSegment|=1;
      else if(Pos2 == IntRes2d_End) PosSegment|=2;
    }
    else if(Pos1 == IntRes2d_End) { 
      if(Pos2 == IntRes2d_Head)     PosSegment|=4;
      else if(Pos2 == IntRes2d_End) PosSegment|=8;
    }

    Pos1 = this->Segment(i).LastPoint().TransitionOfFirst().PositionOnCurve();
    if(Pos1 == IntRes2d_Head)     HeadOn1 = Standard_True;
    else if(Pos1 == IntRes2d_End) EndOn1  = Standard_True;
    
    Pos2 =  this->Segment(i).LastPoint().TransitionOfSecond().PositionOnCurve();
    if(Pos2 == IntRes2d_Head)     HeadOn2 = Standard_True;
    else if(Pos2 == IntRes2d_End) EndOn2  = Standard_True;

    if(Pos1 == IntRes2d_Head) { 
      if(Pos2 == IntRes2d_Head)     PosSegment|=1;
      else if(Pos2 == IntRes2d_End) PosSegment|=2;
    }
    else if(Pos1 == IntRes2d_End) { 
      if(Pos2 == IntRes2d_Head)     PosSegment|=4;
      else if(Pos2 == IntRes2d_End) PosSegment|=8;
    }
  }

  Standard_Real U0 = D1.FirstParameter();
  Standard_Real U1 = D1.LastParameter();
  Standard_Real V0 = D2.FirstParameter();
  Standard_Real V1 = D2.LastParameter();
  IntRes2d_IntersectionPoint IntPt;
  
  if(D1.FirstTolerance() || D2.FirstTolerance()) { 
    if(HeadOrEndPoint(D1,C1,U0,D2,C2,V0,TheTolConf,IntPt,HeadOn1,HeadOn2,EndOn1,EndOn2,PosSegment)) 
      this->Insert(IntPt);
  }
  if(D1.FirstTolerance() || D2.LastTolerance()) { 
    if(HeadOrEndPoint(D1,C1,U0,D2,C2,V1,TheTolConf,IntPt,HeadOn1,HeadOn2,EndOn1,EndOn2,PosSegment)) 
      this->Insert(IntPt);
  }
  if(D1.LastTolerance() || D2.FirstTolerance()) {
    if(HeadOrEndPoint(D1,C1,U1,D2,C2,V0,TheTolConf,IntPt,HeadOn1,HeadOn2,EndOn1,EndOn2,PosSegment)) 
      this->Insert(IntPt);
  }
  if(D1.LastTolerance() ||  D2.LastTolerance()) { 
    if(HeadOrEndPoint(D1,C1,U1,D2,C2,V1,TheTolConf,IntPt,HeadOn1,HeadOn2,EndOn1,EndOn2,PosSegment)) 
      this->Insert(IntPt);
  }
}


//======================================================================
//==      A u t o   I n t e r s e c t i o  n 
//======================================================================
void IntCurve_IntPolyPolyGen::Perform( const TheCurve& C1
				      ,const IntRes2d_Domain& D1
				      ,const Standard_Real TheTolConf
				      ,const Standard_Real TheTol)
{

  this->ResetFields();
  DomainOnCurve1=D1;
  DomainOnCurve2=D1; 
  Standard_Real DU = D1.LastParameter()-D1.FirstParameter();
  Standard_Real Tl=(TheTol < TOL_MINI)? TOL_MINI : TheTol;
  Standard_Real TlConf=(TheTolConf < TOL_CONF_MINI)? TOL_CONF_MINI : TheTolConf;
  Perform(C1,D1,TlConf,Tl,0,DU,DU);
  Standard_Integer i;
  Standard_Integer n=this->NbPoints();

  //--------------------------------------------------------------------
   //-- The points Head Head ... End End are not rejected if
  //-- they are already present at the end of segment 
  //-- ( It is not possible to test the equities on the parameters)
  //-- ( these points are not found at EpsX precision    )
  //-- PosSegment =            1    if Head Head
  //--                       2      if Head End
  //--                     4        if End  Head
  //--                   8          if End  End
  //--------------------------------------------------------------------
  Standard_Integer PosSegment = 0;

  for(i=1;i<=n;i++) { 
    IntRes2d_Position Pos1 = this->Point(i).TransitionOfFirst().PositionOnCurve();
    IntRes2d_Position Pos2 =  this->Point(i).TransitionOfSecond().PositionOnCurve();

    if(Pos1 == IntRes2d_Head) { 
      if(Pos2 == IntRes2d_Head)     PosSegment|=1;
      else if(Pos2 == IntRes2d_End) PosSegment|=2;
    }
    else if(Pos1 == IntRes2d_End) { 
      if(Pos2 == IntRes2d_Head)     PosSegment|=4;
      else if(Pos2 == IntRes2d_End) PosSegment|=8;
    }
  }
  
  n=this->NbSegments();
  for(i=1;i<=n;i++) { 
    IntRes2d_Position Pos1 = this->Segment(i).FirstPoint().TransitionOfFirst().PositionOnCurve();
    IntRes2d_Position Pos2 =  this->Segment(i).FirstPoint().TransitionOfSecond().PositionOnCurve();

    if(Pos1 == IntRes2d_Head) { 
      if(Pos2 == IntRes2d_Head)     PosSegment|=1;
      else if(Pos2 == IntRes2d_End) PosSegment|=2;
    }
    else if(Pos1 == IntRes2d_End) { 
      if(Pos2 == IntRes2d_Head)     PosSegment|=4;
      else if(Pos2 == IntRes2d_End) PosSegment|=8;
    }

    Pos1 = this->Segment(i).LastPoint().TransitionOfFirst().PositionOnCurve();
    Pos2 =  this->Segment(i).LastPoint().TransitionOfSecond().PositionOnCurve();

    if(Pos1 == IntRes2d_Head) { 
      if(Pos2 == IntRes2d_Head)     PosSegment|=1;
      else if(Pos2 == IntRes2d_End) PosSegment|=2;
    }
    else if(Pos1 == IntRes2d_End) { 
      if(Pos2 == IntRes2d_Head)     PosSegment|=4;
      else if(Pos2 == IntRes2d_End) PosSegment|=8;
    }
  }
  (void )PosSegment;
}
//======================================================================

void IntCurve_IntPolyPolyGen::Perform( const TheCurve& C1
				      ,const IntRes2d_Domain& D1
				      ,const Standard_Real TolConf
				      ,const Standard_Real Tol
				      ,const Standard_Integer NbIter
				      ,const Standard_Real /*DeltaU*/
				      ,const Standard_Real) {
  
  gp_Vec2d Tan1,Tan2,Norm1,Norm2;
  gp_Pnt2d P1,P2;
  Standard_Integer nbsamples;
  done = Standard_False;
  
  nbsamples = TheCurveTool::NbSamples(C1,D1.FirstParameter(),D1.LastParameter());

  if(NbIter>3 || (NbIter>2 && nbsamples>100)) return;

  nbsamples*=2;   //---  We take systematically two times more points 
                  //--   than on a normal curve.  
                  //--   Auto-intersecting curves often produce  
                  //--   polygons rather far from the curve with parameter ct.

  if(NbIter>0) { 
    nbsamples=(3*(nbsamples*NbIter))/2;
  }
  IntCurve_ThePolygon2d Poly1(C1,nbsamples,D1,Tol);
  if(!Poly1.AutoIntersectionIsPossible()) { 
    done = Standard_True;
    return;
  }
  //-- Poly1.Dump();
  //----------------------------------------------------------------------
  //-- If the deflection is less than the Tolerance of Confusion
  //-- then the deflection of the polygon is set in TolConf
  //-- (Detection of Tangency Zones)
  //----------------------------------------------------------------------
  if(Poly1.DeflectionOverEstimation() < TolConf) { 
    Poly1.SetDeflectionOverEstimation(TolConf);
  }

  Intf_InterferencePolygon2d InterPP(Poly1);  
  IntCurve_ExactIntersectionPoint  EIP(C1,C1,TolConf);
  Standard_Real U,V;
  
  //----------------------------------------------------------------------
  //-- Processing of SectionPoint 
  //----------------------------------------------------------------------
  Standard_Integer Nbsp = InterPP.NbSectionPoints();
  if(Nbsp>=1) {
    
    //-- ---------------------------------------------------------------------
    //-- filtering, filtering, filtering ...
    //-- 
    Standard_Integer* TriIndex     = new Standard_Integer [Nbsp+1];
    Standard_Integer* PtrSegIndex1 = new Standard_Integer [Nbsp+1];
    Standard_Integer* PtrSegIndex2 = new Standard_Integer [Nbsp+1];
    Standard_Boolean Triok;
    Standard_Integer SegIndex1,SegIndex2,SegIndex_1,SegIndex_2;
//    Standard_Real    ParamOn1,ParamOn2,ParamOn_1,ParamOn_2;
    Standard_Real    ParamOn1,ParamOn2;
    Intf_PIType      Type; 
    Standard_Integer i ;
    for( i=1;i<=Nbsp;i++) { 
      TriIndex[i]=i;
      const Intf_SectionPoint& SPnt1 = InterPP.PntValue(i);
      SPnt1.InfoFirst(Type,PtrSegIndex1[i],ParamOn1);
      SPnt1.InfoSecond(Type,PtrSegIndex2[i],ParamOn2);
    }
 

    do { 
      Triok=Standard_True;

      for(Standard_Integer tr=1;tr<Nbsp;tr++) { 
	      SegIndex1=PtrSegIndex1[TriIndex[tr]];
	      SegIndex_1=PtrSegIndex1[TriIndex[tr+1]];

	      SegIndex2=PtrSegIndex2[TriIndex[tr]];
	      SegIndex_2=PtrSegIndex2[TriIndex[tr+1]];

	      if(SegIndex1 > SegIndex_1) { 
	        Standard_Integer q=TriIndex[tr]; 
	        TriIndex[tr]=TriIndex[tr+1];
	        TriIndex[tr+1]=q;
	        Triok=Standard_False;
	      }
	      else if(SegIndex1 == SegIndex_1) { 
	        if(SegIndex2 > SegIndex_2) { 
	          Standard_Integer q=TriIndex[tr]; 
	          TriIndex[tr]=TriIndex[tr+1];
	          TriIndex[tr+1]=q;
	          Triok=Standard_False;
	        }
	      }
      }
    }
    while(Triok==Standard_False);

    //-- supression des doublons Si Si !
    for(i=1; i<Nbsp;i++) { 
      if(   (PtrSegIndex1[TriIndex[i]] == PtrSegIndex1[TriIndex[i+1]])
	        && (PtrSegIndex2[TriIndex[i]] == PtrSegIndex2[TriIndex[i+1]])) { 
	      TriIndex[i]=-i;
      }
    }

    for(Standard_Integer sp=1; sp <= Nbsp; sp++) {
      if(TriIndex[sp]>0) { 
	      const Intf_SectionPoint& SPnt = InterPP.PntValue(TriIndex[sp]);
      	
	      SPnt.InfoFirst(Type,SegIndex1,ParamOn1);
	      SPnt.InfoSecond(Type,SegIndex2,ParamOn2);
      	
	      if(Abs(SegIndex1-SegIndex2)>1) { 
	  
	        EIP.Perform(Poly1,Poly1,SegIndex1,SegIndex2,ParamOn1,ParamOn2);
	        if(EIP.NbRoots()>=1) { 
	          //--------------------------------------------------------------------
	          //-- It is checked if the found point is a root
	          //--------------------------------------------------------------------
	          EIP.Roots(U,V);

	          TheCurveTool::D1(C1,U,P1,Tan1);
	          TheCurveTool::D1(C1,V,P2,Tan2);
	          Standard_Real Dist = P1.Distance(P2);
	          Standard_Real EpsX1 = 10.0*TheCurveTool::EpsX(C1);
      	    
	          if(Abs(U-V)<=EpsX1) { 
	            //-----------------------------------------
	            //-- Solution not valid 
	            //-- The maths should have converged in a 
	            //-- trivial solution  ( point U = V )
	            //-----------------------------------------
	            Dist = TolConf+1.0;
	          }
      	    
	          //-----------------------------------------------------------------
	          //-- It is checked if the point (u,v) already exists  
	          //--
	          done = Standard_True;
	          Standard_Integer nbp=NbPoints();
      	    
	          for(Standard_Integer p=1; p<=nbp; p++) { 
	            const IntRes2d_IntersectionPoint& P=Point(p);
	            if(Abs(U-P.ParamOnFirst()) <= EpsX1) { 
		            if(Abs(V-P.ParamOnSecond()) <= EpsX1) { 
		              Dist = TolConf+1.0;  p+=nbp;
		            }
	            }
	          }
  	    
	          if(Dist <= TolConf) {    //-- Or the point is already present
	            IntRes2d_Position Pos1 = IntRes2d_Middle;
	            IntRes2d_Position Pos2 = IntRes2d_Middle;
	            IntRes2d_Transition  Trans1,Trans2;
	            //-----------------------------------------------------------------
	            //-- Calculate Positions of Points on the curve
	            //--
	            if(P1.Distance(DomainOnCurve1.FirstPoint())<=DomainOnCurve1.FirstTolerance())    
		            Pos1 = IntRes2d_Head;
	            else if(P1.Distance(DomainOnCurve1.LastPoint())<=DomainOnCurve1.LastTolerance()) 
		            Pos1 = IntRes2d_End;
      	      
	            if(P2.Distance(DomainOnCurve2.FirstPoint())<=DomainOnCurve2.FirstTolerance())    
		            Pos2 = IntRes2d_Head;
	            else if(P2.Distance(DomainOnCurve2.LastPoint())<=DomainOnCurve2.LastTolerance()) 
		            Pos2 = IntRes2d_End;
	            //-----------------------------------------------------------------
	            if(IntImpParGen::DetermineTransition( Pos1,Tan1,Trans1
						         ,Pos2,Tan2,Trans2
						         ,TolConf) == Standard_False) 
              {
		            TheCurveTool::D2(C1,U,P1,Tan1,Norm1);
		            TheCurveTool::D2(C1,V,P2,Tan2,Norm2);
		            IntImpParGen::DetermineTransition( Pos1,Tan1,Norm1,Trans1
						              ,Pos2,Tan2,Norm2,Trans2
						              ,TolConf);
	            }
	            IntRes2d_IntersectionPoint IP(P1,U,V,Trans1,Trans2,Standard_False);
	            Insert(IP);
	          }
	        }
	      }
      }
    }
    delete [] TriIndex;
    delete [] PtrSegIndex1;
    delete [] PtrSegIndex2;
  }

  //----------------------------------------------------------------------
  //-- Processing of TangentZone
  //----------------------------------------------------------------------
  Standard_Integer Nbtz = InterPP.NbTangentZones();
  for(Standard_Integer tz=1; tz <= Nbtz; tz++) {
    Standard_Integer NbPnts = InterPP.ZoneValue(tz).NumberOfPoints();
    //====================================================================
    //== Find the first and the last point in the tangency zone.
    //====================================================================
    Standard_Real ParamSupOnCurve2,ParamInfOnCurve2;
    Standard_Real ParamSupOnCurve1,ParamInfOnCurve1;
//    Standard_Integer SegIndex,SegIndex1onP1,SegIndex1onP2,SegIndex2onP1,SegIndex2onP2;
    Standard_Integer SegIndex1onP1,SegIndex1onP2;
    Intf_PIType Type;
    Standard_Real ParamOnLine;
    Standard_Real PolyUInf,PolyUSup,PolyVInf,PolyVSup;
    ParamSupOnCurve2=ParamSupOnCurve1=PolyUSup=PolyVSup=-RealLast();
    ParamInfOnCurve2=ParamInfOnCurve1=PolyUInf=PolyVInf= RealLast();
    for(Standard_Integer qq=1;qq<=NbPnts;qq++) { 
      const Intf_SectionPoint& SPnt1 = InterPP.ZoneValue(tz).GetPoint(qq);
      //====================================================================
      //== The zones of tangency are discretized 
      //== Test of stop : Check if 
      //==     (Deflection  < Tolerance)
      //==  Or (Sample < EpsX)   (normally the first condition is 
      //==                           more strict)
      //====================================================================
//      Standard_Real _PolyUInf,_PolyUSup,_PolyVInf,_PolyVSup;
      Standard_Real _PolyUInf,_PolyVInf;

      SPnt1.InfoFirst(Type,SegIndex1onP1,ParamOnLine);
      if(SegIndex1onP1 > Poly1.NbSegments()) { SegIndex1onP1--; ParamOnLine = 1.0; }
      if(SegIndex1onP1 <= 0) { SegIndex1onP1=1; ParamOnLine = 0.0; }
      _PolyUInf = Poly1.ApproxParamOnCurve(SegIndex1onP1,ParamOnLine);
      
      SPnt1.InfoSecond(Type,SegIndex1onP2,ParamOnLine);
      if(SegIndex1onP2 > Poly1.NbSegments()) { SegIndex1onP2--; ParamOnLine = 1.0; }
      if(SegIndex1onP2 <= 0) { SegIndex1onP2=1; ParamOnLine = 0.0; }
      _PolyVInf = Poly1.ApproxParamOnCurve(SegIndex1onP2,ParamOnLine);
      
      //----------------------------------------------------------------------

      if(ParamInfOnCurve1 > _PolyUInf) ParamInfOnCurve1=_PolyUInf;
      if(ParamInfOnCurve2 > _PolyVInf) ParamInfOnCurve2=_PolyVInf;

      if(ParamSupOnCurve1 < _PolyUInf) ParamSupOnCurve1=_PolyUInf;
      if(ParamSupOnCurve2 < _PolyVInf) ParamSupOnCurve2=_PolyVInf;
    }

    PolyUInf= ParamInfOnCurve1;
    PolyUSup= ParamSupOnCurve1;
    PolyVInf= ParamInfOnCurve2;
    PolyVSup= ParamSupOnCurve2;
    
    TheCurveTool::D0(C1,PolyUInf,P1);
    TheCurveTool::D0(C1,PolyVInf,P2);
    Standard_Real distmemesens = P1.SquareDistance(P2);
    TheCurveTool::D0(C1,PolyVSup,P2);
    Standard_Real distdiffsens = P1.SquareDistance(P2);
    if(distmemesens > distdiffsens) { 
      Standard_Real qwerty=PolyVInf; PolyVInf=PolyVSup; PolyVSup=qwerty;
    }

    //-----------------------------------------------------------------
    //-- Calculate Positions of Points on the curve and  
    //-- Transitions on each limit of the segment
    
    IntRes2d_Position Pos1 = IntRes2d_Middle;
    IntRes2d_Position Pos2 = IntRes2d_Middle;
    IntRes2d_Transition  Trans1,Trans2;
    
    TheCurveTool::D1(C1,PolyUInf,P1,Tan1);
    TheCurveTool::D1(C1,PolyVInf,P2,Tan2);
    
    if(P1.Distance(DomainOnCurve1.FirstPoint())<=DomainOnCurve1.FirstTolerance())    { 
      Pos1 = IntRes2d_Head;
    }
    else if(P1.Distance(DomainOnCurve1.LastPoint())<=DomainOnCurve1.LastTolerance()) { 
      Pos1 = IntRes2d_End;  
    }
    if(P2.Distance(DomainOnCurve2.FirstPoint())<=DomainOnCurve2.FirstTolerance())    { 
      Pos2 = IntRes2d_Head; 
    }
    else if(P2.Distance(DomainOnCurve2.LastPoint())<=DomainOnCurve2.LastTolerance()) { 
      Pos2 = IntRes2d_End;  
    }
    
    if(Pos1==IntRes2d_Middle && Pos2!=IntRes2d_Middle) { 
      PolyUInf=TheProjPCur::FindParameter( C1,P2,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
    }
    else if(Pos1!=IntRes2d_Middle && Pos2==IntRes2d_Middle) { 
      PolyVInf=TheProjPCur::FindParameter( C1,P1,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
    }
    else if(Abs(ParamInfOnCurve1-ParamSupOnCurve1) > Abs(ParamInfOnCurve2-ParamSupOnCurve2)) { 
      PolyVInf=TheProjPCur::FindParameter( C1,P1,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
    }
    else { 
      PolyUInf=TheProjPCur::FindParameter( C1,P2,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
    }
    

    
    if(IntImpParGen::DetermineTransition( Pos1,Tan1,Trans1,Pos2,Tan2,Trans2,TolConf) 
       == Standard_False)
    {
      TheCurveTool::D2(C1,PolyUInf,P1,Tan1,Norm1);
      TheCurveTool::D2(C1,PolyVInf,P2,Tan2,Norm2);
      IntImpParGen::DetermineTransition(Pos1,Tan1,Norm1,Trans1,
                                        Pos2,Tan2,Norm2,Trans2,TolConf);
    }
    IntRes2d_IntersectionPoint PtSeg1(P1,PolyUInf,PolyVInf
					,Trans1,Trans2,Standard_False);
    //----------------------------------------------------------------------
    
    if((Abs(PolyUInf-PolyUSup) <= TheCurveTool::EpsX(C1)) ||
       (Abs(PolyVInf-PolyVSup) <= TheCurveTool::EpsX(C1)))
    { 
      //bad segment
    }
    else 
    { 
      TheCurveTool::D1(C1,PolyUSup,P1,Tan1);
      TheCurveTool::D1(C1,PolyVSup,P2,Tan2);
      Pos1 = IntRes2d_Middle; Pos2 = IntRes2d_Middle;
      
      if(P1.Distance(DomainOnCurve1.FirstPoint())<=DomainOnCurve1.FirstTolerance())    { 
        Pos1 = IntRes2d_Head; 
      }
      else if(P1.Distance(DomainOnCurve1.LastPoint())<=DomainOnCurve1.LastTolerance()) { 
        Pos1 = IntRes2d_End;  
      }
      if(P2.Distance(DomainOnCurve2.FirstPoint())<=DomainOnCurve2.FirstTolerance())    { 
        Pos2 = IntRes2d_Head; 
      }
      else if(P2.Distance(DomainOnCurve2.LastPoint())<=DomainOnCurve2.LastTolerance()) { 
        Pos2 = IntRes2d_End;  
      }
      
      
      if(Pos1==IntRes2d_Middle && Pos2!=IntRes2d_Middle) { 
        PolyUSup=TheProjPCur::FindParameter( C1,P2,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
      }
      else if(Pos1!=IntRes2d_Middle && Pos2==IntRes2d_Middle) { 
        PolyVSup=TheProjPCur::FindParameter( C1,P1,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
      }
      else if(Abs(ParamInfOnCurve1-ParamSupOnCurve1) > Abs(ParamInfOnCurve2-ParamSupOnCurve2)) { 
        PolyVSup=TheProjPCur::FindParameter( C1,P1,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
      }
      else { 
        PolyUSup=TheProjPCur::FindParameter( C1,P2,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
      }
      
      if(IntImpParGen::DetermineTransition( Pos1,Tan1,Trans1,Pos2,Tan2,Trans2,TolConf)
         ==Standard_False) { 
        TheCurveTool::D2(C1,PolyUSup,P1,Tan1,Norm1);
        TheCurveTool::D2(C1,PolyVSup,P2,Tan2,Norm2);
        IntImpParGen::DetermineTransition(Pos1,Tan1,Norm1,Trans1,
                                          Pos2,Tan2,Norm2,Trans2,TolConf);
      }
      IntRes2d_IntersectionPoint PtSeg2(P1,PolyUSup,PolyVSup
                                        ,Trans1,Trans2,Standard_False);
      
      Standard_Boolean Oppos = (Tan1.Dot(Tan2) > 0.0)? Standard_False : Standard_True;
      if(ParamInfOnCurve1 > ParamSupOnCurve1) {
        IntRes2d_IntersectionSegment Seg(PtSeg2,PtSeg1,Oppos,Standard_False);
        Append(Seg);
      }
      else { 
        IntRes2d_IntersectionSegment Seg(PtSeg1,PtSeg2,Oppos,Standard_False);
        Append(Seg);
      }
    }
  } //end of processing of TangentZone
  
 done = Standard_True;
}


Standard_Boolean HeadOrEndPoint( const IntRes2d_Domain& D1
				,const TheCurve& C1
				,const Standard_Real tu
				,const IntRes2d_Domain& D2
				,const TheCurve& C2
				,const Standard_Real tv
				,const Standard_Real TolConf
				,IntRes2d_IntersectionPoint& IntPt
				,Standard_Boolean& HeadOn1
				,Standard_Boolean& HeadOn2
				,Standard_Boolean& EndOn1
				,Standard_Boolean& EndOn2
				,Standard_Integer PosSegment) { 

  gp_Pnt2d P1,P2,SP1,SP2;
  gp_Vec2d T1,T2,N1,N2;
  Standard_Real u=tu;
  Standard_Real v=tv;
  Standard_Real svu = u;
  Standard_Real svv = v;

  TheCurveTool::D1(C1,u,P1,T1);
  TheCurveTool::D1(C2,v,P2,T2);
  
  IntRes2d_Position Pos1 = IntRes2d_Middle; 
  IntRes2d_Position Pos2 = IntRes2d_Middle;
  IntRes2d_Transition Trans1,Trans2;

  //----------------------------------------------------------------------
  //-- Head On 1   :        Head1 <-> P2
  if(P2.Distance(D1.FirstPoint())<=D1.FirstTolerance())    { 
    Pos1 = IntRes2d_Head; 
    HeadOn1 = Standard_True; 
    SP1 = D1.FirstPoint();
    u = D1.FirstParameter();
  }
  //----------------------------------------------------------------------
  //-- End On 1   :         End1 <-> P2
  else if(P2.Distance(D1.LastPoint())<=D1.LastTolerance()) { 
    Pos1 = IntRes2d_End; 
    EndOn1 = Standard_True;
    SP1 = D1.LastPoint();
    u = D1.LastParameter();
  }

  //----------------------------------------------------------------------
  //-- Head On 2   :        Head2 <-> P1
  else if(P1.Distance(D2.FirstPoint())<=D2.FirstTolerance())    { 
    Pos2 = IntRes2d_Head; 
    HeadOn2 = Standard_True; 
    SP2 = D2.FirstPoint();
    v = D2.FirstParameter();
  }
  //----------------------------------------------------------------------
  //-- End On 2   :        End2 <-> P1
  else if(P1.Distance(D2.LastPoint())<=D2.LastTolerance()) { 
    Pos2 = IntRes2d_End; 
    EndOn2 = Standard_True;
    SP2 = D2.LastPoint();
    v = D2.LastParameter();
  }

  Standard_Real EpsX1 = TheCurveTool::EpsX(C1);
  Standard_Real EpsX2 = TheCurveTool::EpsX(C2);

  if((Pos1 != IntRes2d_Middle)||(Pos2 !=  IntRes2d_Middle)) { 
    if(Pos1 == IntRes2d_Middle) {
      if(Abs(u-D1.FirstParameter()) <= EpsX1) { 
	      Pos1 = IntRes2d_Head;
	      P1 = D1.FirstPoint();
	      HeadOn1 = Standard_True;
      }
      else if(Abs(u-D1.LastParameter()) <= EpsX1) { 
	      Pos1 = IntRes2d_End;
	      P1 = D1.LastPoint();
	      EndOn1 = Standard_True;
      }
    }
    else if(u!=tu) {
      P1 = SP1; 
    }
      
    
    if(Pos2 == IntRes2d_Middle) { 
      if(Abs(v-D2.FirstParameter()) <= EpsX2) { 
	      Pos2 = IntRes2d_Head;
	      HeadOn2 = Standard_True;
	      P2 = D2.FirstPoint();	
	      if(Pos1 != IntRes2d_Middle) {
	        P1.SetCoord(0.5*(P1.X()+P2.X()),0.5*(P1.Y()+P2.Y()));
	      }
	      else { 
	        P2 = P1; 
	      }
      }
      else if(Abs(v-D2.LastParameter()) <= EpsX2) { 
	      Pos2 = IntRes2d_End;
	      EndOn2 = Standard_True;
	      P2 = D2.LastPoint();
	      if(Pos1 != IntRes2d_Middle) {
	        P1.SetCoord(0.5*(P1.X()+P2.X()),0.5*(P1.Y()+P2.Y()));
	      }
	      else { 
	        P2 = P1; 
	      }
      }
    }

    //--------------------------------------------------------------------
    //-- It is tested if a point at the end of segment already has its transitions
    //-- If Yes, the new point is not created
    //-- 
    //-- PosSegment =            1    if Head Head
    //--                       2      if Head End
    //--                     4        if End  Head
    //--                   8          if End  End
    //--------------------------------------------------------------------
    if(Pos1 == IntRes2d_Head) { 
      if((Pos2 == IntRes2d_Head)&&(PosSegment & 1)) return(Standard_False);
      if((Pos2 == IntRes2d_End )&&(PosSegment & 2)) return(Standard_False);
    }
    else if(Pos1 == IntRes2d_End) { 
      if((Pos2 == IntRes2d_Head)&&(PosSegment & 4)) return(Standard_False);
      if((Pos2 == IntRes2d_End )&&(PosSegment & 8)) return(Standard_False);
    }


    if(IntImpParGen::DetermineTransition( Pos1,T1,Trans1,Pos2,T2,Trans2,TolConf)
       == Standard_False) { 
      TheCurveTool::D2(C1,svu,P1,T1,N1);
      TheCurveTool::D2(C2,svv,P2,T2,N2);
      IntImpParGen::DetermineTransition(Pos1,T1,N1,Trans1,
					Pos2,T2,N2,Trans2,TolConf);
    }
    IntPt.SetValues(P1,u,v,Trans1,Trans2,Standard_False);
    return(Standard_True);
  }
  else 
    return(Standard_False);
}

//=======================================================================
//function : Perform
//purpose  : Base method to perform polyline / polyline intersection for
//           pair of curves.
//=======================================================================
void IntCurve_IntPolyPolyGen::Perform(const TheCurve& C1,
                                      const IntRes2d_Domain& D1,
                                      const TheCurve& C2,
                                      const IntRes2d_Domain& D2,
                                      const Standard_Real TolConf,
                                      const Standard_Real Tol,
                                      const Standard_Integer NbIter,
                                      const Standard_Real DeltaU,
                                      const Standard_Real DeltaV)
{
  Standard_Integer nbsamplesOnC1,nbsamplesOnC2;
  done = Standard_False;

  if(NbIter>NBITER_MAX_POLYGON) return;

  // Number of samples running.
  nbsamplesOnC1 = TheCurveTool::NbSamples(C1,D1.FirstParameter(),D1.LastParameter());
  nbsamplesOnC2 = TheCurveTool::NbSamples(C2,D2.FirstParameter(),D2.LastParameter());

  if (NbIter == 0)
  {
    // Minimal number of points.
    nbsamplesOnC1 = Max(nbsamplesOnC1, myMinPntNb);
    nbsamplesOnC2 = Max(nbsamplesOnC2, myMinPntNb);
  }
  else
  {
    // Increase number of samples in second and next iterations.
    nbsamplesOnC1=(5 * (nbsamplesOnC1 * NbIter)) / 4;
    nbsamplesOnC2=(5 * (nbsamplesOnC2 * NbIter)) / 4;
  }

  NCollection_Handle<IntCurve_ThePolygon2d>
    aPoly1 = new IntCurve_ThePolygon2d(C1,nbsamplesOnC1,D1,Tol),
    aPoly2 = new IntCurve_ThePolygon2d(C2,nbsamplesOnC2,D2,Tol);

  if( (aPoly1->DeflectionOverEstimation() > TolConf) &&
      (aPoly2->DeflectionOverEstimation() > TolConf))
  {
    const Standard_Real aDeflectionSum = 
      Max(aPoly1->DeflectionOverEstimation(), TolConf) + 
      Max(aPoly2->DeflectionOverEstimation(), TolConf);

    if (nbsamplesOnC2 > nbsamplesOnC1)
    {
      aPoly2->ComputeWithBox(C2, aPoly1->Bounding());
      aPoly1->SetDeflectionOverEstimation(aDeflectionSum);
      aPoly1->ComputeWithBox(C1, aPoly2->Bounding());
    }
    else
    {
      aPoly1->ComputeWithBox(C1, aPoly2->Bounding());
      aPoly2->SetDeflectionOverEstimation(aDeflectionSum);
      aPoly2->ComputeWithBox(C2, aPoly1->Bounding());
    }
  }

  //----------------------------------------------------------------------
  //-- if the deflection less then the Tolerance of Confusion
  //-- Then the deflection of the polygon is set in TolConf
  //-- (Detection of Tangency Zones)
  //----------------------------------------------------------------------

  if(aPoly1->DeflectionOverEstimation() < TolConf) { 
    aPoly1->SetDeflectionOverEstimation(TolConf);
  }
  if(aPoly2->DeflectionOverEstimation() < TolConf) { 
    aPoly2->SetDeflectionOverEstimation(TolConf);
  }
  // for case when a few polygon points were replaced by line
  // if exact solution was not found 
  // then search of precise solution will be repeated 
  // for polygon contains all initial points
  // secondary search will be performed only for case when initial points
  // were dropped
  Standard_Boolean isFullRepresentation = ( aPoly1->NbSegments() == nbsamplesOnC1 && 
	    aPoly2->NbSegments() == nbsamplesOnC2 );
  
  if( !findIntersect( C1, D1, C2, D2, TolConf, Tol, NbIter,
	  DeltaU, DeltaV, *aPoly1, *aPoly2, isFullRepresentation ) && !isFullRepresentation ) 
  {
    if(aPoly1->NbSegments() < nbsamplesOnC1)
    {
      aPoly1 = new IntCurve_ThePolygon2d(C1,nbsamplesOnC1,D1,Tol);
    }
    if(aPoly2->NbSegments() < nbsamplesOnC2)
    {
      aPoly2 = new IntCurve_ThePolygon2d(C2,nbsamplesOnC2,D2,Tol);
    }

    findIntersect( C1, D1, C2, D2, TolConf, Tol, NbIter,
      DeltaU, DeltaV, *aPoly1, *aPoly2, 
      Standard_True);	

  }
 
  done = Standard_True;
}

//======================================================================
// Purpose : findIntersect
//======================================================================

Standard_Boolean IntCurve_IntPolyPolyGen::findIntersect( 
    const TheCurve& C1,
	  const IntRes2d_Domain& D1,
	  const TheCurve& C2,
	  const IntRes2d_Domain& D2,
	  const Standard_Real TolConf,
	  const Standard_Real Tol,
	  const Standard_Integer NbIter,
	  const Standard_Real DeltaU,
	  const Standard_Real DeltaV,
	  const IntCurve_ThePolygon2d& thePoly1,
	  const IntCurve_ThePolygon2d& thePoly2,
	  Standard_Boolean isFullPolygon )
{

  gp_Vec2d Tan1,Tan2,Norm1,Norm2;
  gp_Pnt2d P1,P2;
  Intf_InterferencePolygon2d InterPP(thePoly1,thePoly2);  
  IntCurve_ExactIntersectionPoint  EIP(C1,C2,TolConf);
  Standard_Real U = 0., V = 0.;
  Standard_Boolean AnErrorOccurred = Standard_False;
  done = Standard_True; // To prevent exception in nbp=NbPoints();
  //----------------------------------------------------------------------
  //-- Processing of SectionPoint 
  //----------------------------------------------------------------------
  Standard_Integer Nbsp = InterPP.NbSectionPoints();
  for(Standard_Integer sp=1; sp <= Nbsp; sp++) {
    const Intf_SectionPoint& SPnt = InterPP.PntValue(sp);
    Standard_Integer SegIndex1,SegIndex2;
    Standard_Real    ParamOn1,ParamOn2;
    Intf_PIType      Type;

    SPnt.InfoFirst(Type,SegIndex1,ParamOn1);
    SPnt.InfoSecond(Type,SegIndex2,ParamOn2);
    EIP.Perform(thePoly1,thePoly2,SegIndex1,SegIndex2,ParamOn1,ParamOn2);
    AnErrorOccurred = EIP.AnErrorOccurred();

    if( !EIP.NbRoots() && !isFullPolygon)
      return Standard_False;

    if(AnErrorOccurred) 
    {
      continue;
    }

    //--------------------------------------------------------------------
    //-- It is checked if the found point is really a root
    //--------------------------------------------------------------------

    EIP.Roots(U,V);
    TheCurveTool::D1(C1,U,P1,Tan1);
    TheCurveTool::D1(C2,V,P2,Tan2);
    Standard_Real Dist = P1.Distance(P2);
    if(EIP.NbRoots() == 0 && Dist > TolConf)
    {
      IntRes2d_Transition aTrans;
      IntRes2d_IntersectionPoint aPInt(P1, U, V, aTrans, aTrans, Standard_False);
      Standard_Real aT1f, aT1l, aT2f, aT2l;
      aT1f= thePoly1.ApproxParamOnCurve(SegIndex1, 0.0); 
      aT1l= thePoly1.ApproxParamOnCurve(SegIndex1, 1.0); 
      aT2f= thePoly2.ApproxParamOnCurve(SegIndex2, 0.0); 
      aT2l= thePoly2.ApproxParamOnCurve(SegIndex2, 1.0); 
      //
      Standard_Integer aMaxCount = 16, aCount = 0;
      GetIntersection(C1, aT1f, aT1l, C2, aT2f, aT2l, TolConf, aMaxCount, 
                      aPInt, Dist, aCount); 
      U = aPInt.ParamOnFirst();
      V = aPInt.ParamOnSecond();
      TheCurveTool::D1(C1,U,P1,Tan1);
      TheCurveTool::D1(C2,V,P2,Tan2);
      Dist = P1.Distance(P2);
    }
    //-----------------------------------------------------------------
    //-- It is checked if the point (u,v) does not exist already 
    //--
    Standard_Integer nbp=NbPoints();
    Standard_Real EpsX1 = 10.0*TheCurveTool::EpsX(C1);
    Standard_Real EpsX2 = 10.0*TheCurveTool::EpsX(C2);
    for(Standard_Integer p=1; p<=nbp; p++) { 
      const IntRes2d_IntersectionPoint& P=Point(p);
      if(Abs(U-P.ParamOnFirst()) <= EpsX1) { 
        if(Abs(V-P.ParamOnSecond()) <= EpsX2) { 
          Dist = TolConf+1.0;  p+=nbp;
        }
      }
    }

    if(Dist <= TolConf) {    //-- Or the point is already present
      IntRes2d_Position Pos1 = IntRes2d_Middle;
      IntRes2d_Position Pos2 = IntRes2d_Middle;
      IntRes2d_Transition  Trans1,Trans2;
      //-----------------------------------------------------------------
      //-- Calculate the Positions of Points on the curve
      //--
      if(P1.Distance(DomainOnCurve1.FirstPoint())<=DomainOnCurve1.FirstTolerance())    
        Pos1 = IntRes2d_Head;
      else if(P1.Distance(DomainOnCurve1.LastPoint())<=DomainOnCurve1.LastTolerance()) 
        Pos1 = IntRes2d_End;

      if(P2.Distance(DomainOnCurve2.FirstPoint())<=DomainOnCurve2.FirstTolerance())    
        Pos2 = IntRes2d_Head;
      else if(P2.Distance(DomainOnCurve2.LastPoint())<=DomainOnCurve2.LastTolerance()) 
        Pos2 = IntRes2d_End;
      //-----------------------------------------------------------------
      //-- Calculate the Transitions (see IntImpParGen.cxx)
      //--
      if(IntImpParGen::DetermineTransition (Pos1, Tan1, Trans1, Pos2, Tan2, Trans2, TolConf) == Standard_False) { 
        TheCurveTool::D2(C1,U,P1,Tan1,Norm1);
        TheCurveTool::D2(C2,V,P2,Tan2,Norm2);
        IntImpParGen::DetermineTransition (Pos1, Tan1, Norm1, Trans1, Pos2, Tan2, Norm2, Trans2, TolConf);
      }
      IntRes2d_IntersectionPoint IP(P1,U,V,Trans1,Trans2,Standard_False);
      Insert(IP);
    }
  }
  
  //----------------------------------------------------------------------
  //-- Processing of TangentZone
  //----------------------------------------------------------------------
  Standard_Integer Nbtz = InterPP.NbTangentZones();
  for(Standard_Integer tz=1; tz <= Nbtz; tz++) {
    Standard_Integer NbPnts = InterPP.ZoneValue(tz).NumberOfPoints();
    //====================================================================
    //== Find the first and the last point in the tangency zone.
    //====================================================================
    Standard_Real ParamSupOnCurve2,ParamInfOnCurve2;
    Standard_Real ParamSupOnCurve1,ParamInfOnCurve1;
//    Standard_Integer SegIndex,SegIndex1onP1,SegIndex1onP2,SegIndex2onP1,SegIndex2onP2;
    Standard_Integer SegIndex1onP1,SegIndex1onP2;
    Intf_PIType Type;
    Standard_Real ParamOnLine;
    Standard_Real PolyUInf,PolyUSup,PolyVInf,PolyVSup;
    ParamSupOnCurve2=ParamSupOnCurve1=PolyUSup=PolyVSup=-RealLast();
    ParamInfOnCurve2=ParamInfOnCurve1=PolyUInf=PolyVInf= RealLast();
    for(Standard_Integer qq=1;qq<=NbPnts;qq++) { 
      const Intf_SectionPoint& SPnt1 = InterPP.ZoneValue(tz).GetPoint(qq);
      //====================================================================
      //== The zones of tangency are discretized 
      //== Test of stop : Check if 
      //==     (Deflection  < Tolerance)
      //==  Or (Sample < EpsX)   (normally the first condition is 
      //==                           more strict)
      //====================================================================
//      Standard_Real _PolyUInf,_PolyUSup,_PolyVInf,_PolyVSup;
      Standard_Real _PolyUInf,_PolyVInf;

      SPnt1.InfoFirst(Type,SegIndex1onP1,ParamOnLine);
      if(SegIndex1onP1 > thePoly1.NbSegments()) { SegIndex1onP1--; ParamOnLine = 1.0; }
      if(SegIndex1onP1 <= 0) { SegIndex1onP1=1; ParamOnLine = 0.0; }
      _PolyUInf = thePoly1.ApproxParamOnCurve(SegIndex1onP1,ParamOnLine);
      
      SPnt1.InfoSecond(Type,SegIndex1onP2,ParamOnLine);
      if(SegIndex1onP2 > thePoly2.NbSegments()) { SegIndex1onP2--; ParamOnLine = 1.0; }
      if(SegIndex1onP2 <= 0) { SegIndex1onP2=1; ParamOnLine = 0.0; }
      _PolyVInf = thePoly2.ApproxParamOnCurve(SegIndex1onP2,ParamOnLine);
      
      //----------------------------------------------------------------------

      if(ParamInfOnCurve1 > _PolyUInf) ParamInfOnCurve1=_PolyUInf;
      if(ParamInfOnCurve2 > _PolyVInf) ParamInfOnCurve2=_PolyVInf;

      if(ParamSupOnCurve1 < _PolyUInf) ParamSupOnCurve1=_PolyUInf;
      if(ParamSupOnCurve2 < _PolyVInf) ParamSupOnCurve2=_PolyVInf;
    }

    PolyUInf= ParamInfOnCurve1;
    PolyUSup= ParamSupOnCurve1;
    PolyVInf= ParamInfOnCurve2;
    PolyVSup= ParamSupOnCurve2;
    
    TheCurveTool::D0(C1,PolyUInf,P1);
    TheCurveTool::D0(C2,PolyVInf,P2);
    Standard_Real distmemesens = P1.SquareDistance(P2);
    TheCurveTool::D0(C2,PolyVSup,P2);
    Standard_Real distdiffsens = P1.SquareDistance(P2);
    if(distmemesens > distdiffsens) { 
      Standard_Real qwerty=PolyVInf; PolyVInf=PolyVSup; PolyVSup=qwerty;
    }

    if(  (  (thePoly1.DeflectionOverEstimation() > TolConf)
	    ||(thePoly2.DeflectionOverEstimation() > TolConf))
	    &&(NbIter<NBITER_MAX_POLYGON)) {
      
      IntRes2d_Domain RecursD1( TheCurveTool::Value(C1,ParamInfOnCurve1)
			       ,ParamInfOnCurve1,TolConf
			       ,TheCurveTool::Value(C1,ParamSupOnCurve1)
			       ,ParamSupOnCurve1,TolConf);
      IntRes2d_Domain RecursD2( TheCurveTool::Value(C2,ParamInfOnCurve2)
			       ,ParamInfOnCurve2,TolConf
			       ,TheCurveTool::Value(C2,ParamSupOnCurve2)
			       ,ParamSupOnCurve2,TolConf);
      //-- thePoly1(2) are not deleted,
      //-- finally they are destroyed. 
      //-- !! No untimely return !!
      Perform(C1,RecursD1,C2,RecursD2,Tol,TolConf,NbIter+1,DeltaU,DeltaV);
    }
    else { 
      //-----------------------------------------------------------------
      //-- Calculate Positions of Points on the curve and  
      //-- Transitions on each limit of the segment
      
      IntRes2d_Position Pos1 = IntRes2d_Middle;
      IntRes2d_Position Pos2 = IntRes2d_Middle;
      IntRes2d_Transition  Trans1,Trans2;
      
      TheCurveTool::D1(C1,PolyUInf,P1,Tan1);
      TheCurveTool::D1(C2,PolyVInf,P2,Tan2);
      
      if(P1.Distance(DomainOnCurve1.FirstPoint())<=DomainOnCurve1.FirstTolerance())    { 
	      Pos1 = IntRes2d_Head;
      }
      else if(P1.Distance(DomainOnCurve1.LastPoint())<=DomainOnCurve1.LastTolerance()) { 
	      Pos1 = IntRes2d_End;  
      }
      if(P2.Distance(DomainOnCurve2.FirstPoint())<=DomainOnCurve2.FirstTolerance())    { 
	      Pos2 = IntRes2d_Head; 
      }
      else if(P2.Distance(DomainOnCurve2.LastPoint())<=DomainOnCurve2.LastTolerance()) { 
	      Pos2 = IntRes2d_End;  
      }

      if(Pos1==IntRes2d_Middle && Pos2!=IntRes2d_Middle) { 
	      PolyUInf=TheProjPCur::FindParameter( C1,P2,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
      }
      else if(Pos1!=IntRes2d_Middle && Pos2==IntRes2d_Middle) { 
	      PolyVInf=TheProjPCur::FindParameter( C2,P1,D2.FirstParameter(),D2.LastParameter(),TheCurveTool::EpsX(C2));
      }
      else if(Abs(ParamInfOnCurve1-ParamSupOnCurve1) > Abs(ParamInfOnCurve2-ParamSupOnCurve2)) { 
	      PolyVInf=TheProjPCur::FindParameter( C2,P1,D2.FirstParameter(),D2.LastParameter(),TheCurveTool::EpsX(C2));
      }
      else { 
	      PolyUInf=TheProjPCur::FindParameter( C1,P2,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
      }
      


      if(IntImpParGen::DetermineTransition( Pos1,Tan1,Trans1,Pos2,Tan2,Trans2,TolConf) 
	       == Standard_False)
      {
	      TheCurveTool::D2(C1,PolyUInf,P1,Tan1,Norm1);
	      TheCurveTool::D2(C2,PolyVInf,P2,Tan2,Norm2);
	      IntImpParGen::DetermineTransition(Pos1,Tan1,Norm1,Trans1,
					        Pos2,Tan2,Norm2,Trans2,TolConf);
      }
      IntRes2d_IntersectionPoint PtSeg1(P1,PolyUInf,PolyVInf
					,Trans1,Trans2,Standard_False);
      //----------------------------------------------------------------------
      
      if((Abs(PolyUInf-PolyUSup) <= TheCurveTool::EpsX(C1)) 
	      || (Abs(PolyVInf-PolyVSup) <= TheCurveTool::EpsX(C2)))
      { 
	      Insert(PtSeg1);
      }
      else 
      { 
	      TheCurveTool::D1(C1,PolyUSup,P1,Tan1);
	      TheCurveTool::D1(C2,PolyVSup,P2,Tan2);
	      Pos1 = IntRes2d_Middle; Pos2 = IntRes2d_Middle;
	  
	      if(P1.Distance(DomainOnCurve1.FirstPoint())<=DomainOnCurve1.FirstTolerance())    { 
	        Pos1 = IntRes2d_Head; 
	      }
	      else if(P1.Distance(DomainOnCurve1.LastPoint())<=DomainOnCurve1.LastTolerance()) { 
	        Pos1 = IntRes2d_End;  
	      }
	      if(P2.Distance(DomainOnCurve2.FirstPoint())<=DomainOnCurve2.FirstTolerance())    { 
	        Pos2 = IntRes2d_Head; 
	      }
	      else if(P2.Distance(DomainOnCurve2.LastPoint())<=DomainOnCurve2.LastTolerance()) { 
	        Pos2 = IntRes2d_End;  
	      }


	      if(Pos1==IntRes2d_Middle && Pos2!=IntRes2d_Middle) { 
	        PolyUSup=TheProjPCur::FindParameter( C1,P2,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
	      }
	      else if(Pos1!=IntRes2d_Middle && Pos2==IntRes2d_Middle) { 
	        PolyVSup=TheProjPCur::FindParameter( C2,P1,D2.FirstParameter(),D2.LastParameter(),TheCurveTool::EpsX(C2));
	      }
	      else if(Abs(ParamInfOnCurve1-ParamSupOnCurve1) > Abs(ParamInfOnCurve2-ParamSupOnCurve2)) { 
	        PolyVSup=TheProjPCur::FindParameter( C2,P1,D2.FirstParameter(),D2.LastParameter(),TheCurveTool::EpsX(C2));
	      }
	      else { 
	        PolyUSup=TheProjPCur::FindParameter( C1,P2,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
	      }
	
        if(IntImpParGen::DetermineTransition( Pos1,Tan1,Trans1,Pos2,Tan2,Trans2,TolConf)
           ==Standard_False) { 
          TheCurveTool::D2(C1,PolyUSup,P1,Tan1,Norm1);
          TheCurveTool::D2(C2,PolyVSup,P2,Tan2,Norm2);
          IntImpParGen::DetermineTransition(Pos1,Tan1,Norm1,Trans1,
				            Pos2,Tan2,Norm2,Trans2,TolConf);
        }
        IntRes2d_IntersectionPoint PtSeg2(P1,PolyUSup,PolyVSup
				          ,Trans1,Trans2,Standard_False);
	
	      Standard_Boolean Oppos = (Tan1.Dot(Tan2) > 0.0)? Standard_False : Standard_True;
	      if(ParamInfOnCurve1 > ParamSupOnCurve1) {
	        IntRes2d_IntersectionSegment Seg(PtSeg2,PtSeg1,Oppos,Standard_False);
	        Append(Seg);
	      }
	      else { 
	        IntRes2d_IntersectionSegment Seg(PtSeg1,PtSeg2,Oppos,Standard_False);
	        Append(Seg);
	      }
      }
    }
  }
 return Standard_True;
}

//======================================================================
//  GetIntersection
//======================================================================

void GetIntersection(const TheCurve& theC1, const Standard_Real theT1f, const Standard_Real theT1l,
                     const TheCurve& theC2, const Standard_Real theT2f, const Standard_Real theT2l, 
                     const Standard_Real theTolConf,
                     const Standard_Integer theMaxCount,
                     IntRes2d_IntersectionPoint& thePInt, Standard_Real& theDist,
                     Standard_Integer& theCount)
{
  theCount++;
  //
  Standard_Real aTol2 = theTolConf*theTolConf;
  Standard_Real aPTol1 = Max(100.*Epsilon(Max(Abs(theT1f), Abs(theT1l))), Precision::PConfusion());
  Standard_Real aPTol2 = Max(100.*Epsilon(Max(Abs(theT2f), Abs(theT2l))), Precision::PConfusion());
  gp_Pnt2d aP1f, aP1l, aP2f, aP2l;
  Bnd_Box2d aB1, aB2;
  //
  TheCurveTool::D0(theC1, theT1f, aP1f);
  TheCurveTool::D0(theC1, theT1l, aP1l);
  aB1.Add(aP1f);
  aB1.Add(aP1l);
  aB1.Enlarge(theTolConf);
  //
  TheCurveTool::D0(theC2, theT2f, aP2f);
  TheCurveTool::D0(theC2, theT2l, aP2l);
  aB2.Add(aP2f);
  aB2.Add(aP2l);
  aB2.Enlarge(theTolConf);
  //
  if(aB1.IsOut(aB2))
  {
    theCount--;
    return;
  }
  //
  Standard_Boolean isSmall1 = (theT1l - theT1f) <= aPTol1 || aP1f.SquareDistance(aP1l) / 4. <= aTol2;
  Standard_Boolean isSmall2 = (theT2l - theT2f) <= aPTol2 || aP2f.SquareDistance(aP2l) / 4. <= aTol2;

  if((isSmall1 && isSmall2) || (theCount > theMaxCount))
  {
    //Seems to be intersection
    //Simple treatment of segment intersection
    gp_XY aPnts1[3] = {aP1f.XY(), (aP1f.XY() + aP1l.XY()) / 2., aP1l.XY()};
    gp_XY aPnts2[3] = {aP2f.XY(), (aP2f.XY() + aP2l.XY()) / 2., aP2l.XY()};
    Standard_Integer i, j, imin = -1, jmin = -1;
    Standard_Real dmin = RealLast(), d;
    for(i = 0; i < 3; i++)
    {
      for(j = 0; j < 3; j++)
      {
        d = (aPnts1[i] - aPnts2[j]).SquareModulus();
        if(d < dmin)
        {
          dmin=d;
          imin = i;
          jmin = j;
        }
      }
    }
    //
    dmin = Sqrt(dmin);
    if(theDist > dmin)
    {
      theDist = dmin;
      //
      Standard_Real t1;
      if(imin == 0)
      {
        t1 = theT1f;
      }
      else if(imin == 1)
      {
        t1 = (theT1f + theT1l) / 2.;
      }
      else
      {
        t1 = theT1l;
      }
      //
      Standard_Real t2;
      if(jmin == 0)
      {
        t2 = theT2f;
      }
      else if(jmin == 1)
      {
        t2 = (theT2f + theT2l) / 2.;
      }
      else
      {
        t2 = theT2l;
      }
      //
      gp_Pnt2d aPint((aPnts1[imin] + aPnts2[jmin])/2.);
      //
      IntRes2d_Transition aTrans1, aTrans2;
      thePInt.SetValues(aPint, t1, t2, aTrans1, aTrans2, Standard_False);
    }
    theCount--;
    return;
  }

  if(isSmall1)
  {
    Standard_Real aT2m = (theT2l + theT2f) / 2.;
    GetIntersection(theC1, theT1f, theT1l, theC2, theT2f, aT2m, theTolConf, theMaxCount, thePInt, theDist, theCount);
    GetIntersection(theC1, theT1f, theT1l, theC2, aT2m, theT2l, theTolConf, theMaxCount, thePInt, theDist, theCount);
  }
  else if(isSmall2)
  {
    Standard_Real aT1m = (theT1l + theT1f) / 2.;
    GetIntersection(theC1, theT1f, aT1m, theC2, theT2f, theT2l, theTolConf, theMaxCount, thePInt, theDist, theCount);
    GetIntersection(theC1, aT1m, theT1l, theC2, theT2f, theT2l, theTolConf, theMaxCount, thePInt, theDist, theCount);
  }
  else
  {
    Standard_Real aT1m = (theT1l + theT1f) / 2.;
    Standard_Real aT2m = (theT2l + theT2f) / 2.;
    GetIntersection(theC1, theT1f, aT1m, theC2, theT2f, aT2m, theTolConf, theMaxCount, thePInt, theDist, theCount);
    GetIntersection(theC1, theT1f, aT1m, theC2, aT2m, theT2l, theTolConf, theMaxCount, thePInt, theDist, theCount);
    GetIntersection(theC1, aT1m, theT1l, theC2, theT2f, aT2m, theTolConf, theMaxCount, thePInt, theDist, theCount);
    GetIntersection(theC1, aT1m, theT1l, theC2, aT2m, theT2l, theTolConf, theMaxCount, thePInt, theDist, theCount);
  }

}

//=======================================================================
//function : GetMinNbPoints
//purpose  : 
//=======================================================================
Standard_Integer IntCurve_IntPolyPolyGen::GetMinNbSamples() const
{
  return myMinPntNb;
}

//=======================================================================
//function : SetMinNbPoints
//purpose  : 
//=======================================================================
void IntCurve_IntPolyPolyGen::SetMinNbSamples(const Standard_Integer theMinNbSamples)
{
  myMinPntNb = theMinNbSamples;
}
