// File:	BRepExtrema_DistanceSS.cxx
// Created:	Mon Apr 22 17:03:37 1996
// Author:	Maria PUMBORIOS
// Author:      Herve LOUESSARD 
//		<mps@sgi64>


#include <BRepExtrema_DistanceSS.ixx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopExp.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pnt2d.hxx>
#include <BRep_Tool.hxx>
#include <BRepExtrema_SupportType.hxx>
#include <Precision.hxx>
#include <Standard_Real.hxx>
#include <BRepExtrema_SolutionElem.hxx>
#include <BRepExtrema_SeqOfSolution.hxx>
#include <Standard_Boolean.hxx>
#include <Standard_Integer.hxx> 
#include <TopAbs_ShapeEnum.hxx>
#include <TopoDS.hxx>
#include <Bnd_Box.hxx>
#include <BRepExtrema_ExtPC.hxx>
#include <BRepExtrema_ExtPF.hxx>
#include <BRepExtrema_ExtCC.hxx>
#include <BRepExtrema_ExtCF.hxx>
#include <BRepExtrema_ExtFF.hxx>
#include <BRepClass_FaceClassifier.hxx>
#include <TopAbs.hxx>
#include <Geom_Curve.hxx>
#include <GeomAbs_Shape.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <Geom_Surface.hxx>
#include <GeomAPI_ProjectPointOnSurf.hxx>
#include <GeomAPI_ProjectPointOnCurve.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <BRepBndLib.hxx>
#include <BRepTools.hxx>
#include <TColgp_Array1OfPnt.hxx>



/*********************************************************************************/
/*********************************************************************************/

//------------------------------------------------------------------------------
// function: TRI_SOLUTION
//------------------------------------------------------------------------------
void TRI_SOLUTION (const BRepExtrema_SeqOfSolution& SeqSol,
		   const gp_Pnt& Pt, Standard_Boolean& inserer )
{
 inserer = Standard_True;
 Standard_Integer Nbsol= SeqSol.Length();
 Standard_Integer i;
 Standard_Real dst;
 for (i=1;i<=Nbsol;i++)
    {gp_Pnt P1=SeqSol.Value(i).Point();
     dst=P1.Distance(Pt);
     if (dst<=Precision::Confusion()) inserer=Standard_False;}  
}  

//------------------------------------------------------------------------------
// function: MIN_SOLUTION
//------------------------------------------------------------------------------
void MIN_SOLUTION (const BRepExtrema_SeqOfSolution& SeqSol1,
		   const BRepExtrema_SeqOfSolution& SeqSol2,
		   const Standard_Real& DstRef,
		   const Standard_Real& Eps,
		   BRepExtrema_SeqOfSolution& seqSol1,
		   BRepExtrema_SeqOfSolution& seqSol2)
{
  Standard_Real dst1;
  Standard_Integer nbSol = SeqSol1.Length();
  
  for (Standard_Integer i = 1; i<=nbSol; i++)
    {
      dst1 = SeqSol1.Value(i).Dist();
      
      if (fabs(dst1 - DstRef) < Eps)
	{	  
	  seqSol1.Append(SeqSol1.Value(i));
	  seqSol2.Append(SeqSol2.Value(i));	
	}
    }
}


//------------------------------------------------------------------------------
// function: TRIM_INFINIT_EDGE
//------------------------------------------------------------------------------
void TRIM_INFINIT_EDGE(const TopoDS_Edge& S1, 
		       const TopoDS_Edge& S2,		       
		       TopoDS_Edge& aResEdge,
		       Standard_Boolean& bIsTrim1,
		       Standard_Boolean& bIsTrim2)
{
  if ( BRep_Tool::Degenerated(S1) ||
       BRep_Tool::Degenerated(S2) )
    return;

  aResEdge = S2;
  Standard_Real aFirst1, aLast1, aFirst2, aLast2;
  Handle(Geom_Curve) pCurv;
  Handle(Geom_Curve) pCurv1 = BRep_Tool::Curve(S1, aFirst1, aLast1);
  Handle(Geom_Curve) pCurv2 = BRep_Tool::Curve(S2, aFirst2, aLast2);

  Standard_Real Umin, Umax;
  Standard_Boolean bUmin, bUmax;
  bUmin = bUmax = Standard_False;

  if (Precision::IsInfinite(aFirst1) &&
      Precision::IsInfinite(aLast1)  &&
      Precision::IsInfinite(aFirst2) &&
      Precision::IsInfinite(aLast2))
    return;

  
  if ( !pCurv1.IsNull() && (Precision::IsInfinite(aFirst1) ||
			    Precision::IsInfinite(aLast1)) )
    {
      pCurv = pCurv1;
      bIsTrim1 = Standard_True;
      if (!Precision::IsInfinite(aFirst1))
	{
	  bUmin = Standard_True;
	  Umin = aFirst1;
	}
      else if (!Precision::IsInfinite(aLast1))
	{
	  bUmax = Standard_True;
	  Umax = aLast1;
	}
    }
  else if ( !pCurv2.IsNull() && (Precision::IsInfinite(aFirst2) ||
				 Precision::IsInfinite(aLast2)) )
    {
      pCurv = pCurv2;
      bIsTrim2 = Standard_True;
      if (!Precision::IsInfinite(aFirst2))
	{
	  bUmin = Standard_True;
	  Umin = aFirst2;
	}
      else if (!Precision::IsInfinite(aLast2))
	{
	  bUmax = Standard_True;
	  Umax = aLast2;
	}
    }
  if (bIsTrim1 || bIsTrim2)
    {
      Bnd_Box aEdgeBox;
      if (bIsTrim1)
	BRepBndLib::Add(S2, aEdgeBox);
      if (bIsTrim2)
	BRepBndLib::Add(S1, aEdgeBox);
      Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
      aEdgeBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);      


      TColStd_Array1OfReal arrU(1, 8);
      TColgp_Array1OfPnt arrPnt(1, 8);

      gp_Pnt aPnt1(Xmin, Ymin, Zmin);
      arrPnt.SetValue(1, aPnt1);
      gp_Pnt aPnt2(Xmin, Ymax, Zmin);
      arrPnt.SetValue(2, aPnt2);
      gp_Pnt aPnt3(Xmin, Ymax, Zmax);
      arrPnt.SetValue(3, aPnt3);
      gp_Pnt aPnt4(Xmin, Ymin, Zmax);
      arrPnt.SetValue(4, aPnt4);
      gp_Pnt aPnt5(Xmax, Ymax, Zmin);
      arrPnt.SetValue(5, aPnt5);
      gp_Pnt aPnt6(Xmax, Ymax, Zmax);
      arrPnt.SetValue(6, aPnt6);
      gp_Pnt aPnt7(Xmax, Ymin, Zmax);
      arrPnt.SetValue(7, aPnt7);
      gp_Pnt aPnt8(Xmax, Ymin, Zmin);
      arrPnt.SetValue(8, aPnt8);
      
      Standard_Real U;
      Standard_Integer i = 1;

      GeomAPI_ProjectPointOnCurve aProj(aPnt1, pCurv);

      for (i = 1; i <= arrPnt.Length(); i++)
	{
	  gp_Pnt aPnt = arrPnt.Value(i);
	  aProj.Perform(aPnt);
	  U = aProj.LowerDistanceParameter();
	  arrU.SetValue(i, U);
	}

      Standard_Real aU;

      if (!bUmin)
	Umin = arrU.Value(1);
	
      if (!bUmax)
	Umax = arrU.Value(1);

      for(i = 1; i <= arrU.Length(); i++)
	{
	  aU = arrU.Value(i);
	  if (aU < Umin)
	    Umin = aU;
	  else if (aU > Umax)
	    Umax = aU;

	}
      GeomAdaptor_Curve aGAC(pCurv);
      Standard_Real tol = Precision::Confusion();
      if (bIsTrim1)
	tol = BRep_Tool::Tolerance(S1);
      else if (bIsTrim2)
	tol = BRep_Tool::Tolerance(S2);
      
      Standard_Real EpsU = aGAC.Resolution(3*tol);
      if (fabs(Umin - Umax) < EpsU)
	{
	  Umin = Umin - EpsU;
	  Umax = Umax + EpsU;
	}


      Handle(Geom_Curve) result = new Geom_TrimmedCurve(pCurv, Umin, Umax);
      aResEdge = BRepBuilderAPI_MakeEdge(result);
    }
}

//------------------------------------------------------------------------------
// function: TRIM_INFINIT_FACE
//------------------------------------------------------------------------------
void TRIM_INFINIT_FACE(const TopoDS_Shape& S1,
		       const TopoDS_Shape& S2,
		       TopoDS_Face& aResFace,
		       Standard_Boolean& bIsInfinit)
{
  bIsInfinit = Standard_False;

  TopAbs_ShapeEnum       Type1, Type2;
  Type1 = S1.ShapeType();     
  Type2 = S2.ShapeType();

  TopoDS_Edge aE;
  TopoDS_Face aF;
  
  if (Type1 == TopAbs_EDGE && Type2 == TopAbs_FACE)
    {
      aE = TopoDS::Edge(S1);
      if ( BRep_Tool::Degenerated(aE) )
	return;
      aF = TopoDS::Face(S2);
    }
  else if (Type2 == TopAbs_EDGE && Type1 == TopAbs_FACE)
    {
      aE = TopoDS::Edge(S2);
      if ( BRep_Tool::Degenerated(aE) )
	return;
      aF = TopoDS::Face(S1);
    }
  else
    {
      bIsInfinit = Standard_False;
      return;
    }  
  Standard_Real Umin, Umax, Vmin, Vmax;

  Standard_Boolean bIsTrim = Standard_False;
  
  
  aResFace = aF;
  Handle(Geom_Surface) pSurf = BRep_Tool::Surface(aF);
 
  Standard_Real U1, V1, U2, V2;
  
  Standard_Boolean bRestrict = BRep_Tool::NaturalRestriction(aF);

  Standard_Boolean bUmin, bUmax, bVmin, bVmax;
  bUmin = bUmax = bVmin = bVmax = Standard_False;

  if (bRestrict)
    {
      pSurf->Bounds(U1, U2, V1, V2);
      if (Precision::IsInfinite(U1))
	bIsTrim = Standard_True;
      else
	{
	  Umin = U1;
	  bUmin = Standard_True;
	}

      if (Precision::IsInfinite(U2))
	bIsTrim = Standard_True;
      else
	{
	  Umax = U2;
	  bUmax = Standard_True;
	}

      if (Precision::IsInfinite(V1))
	bIsTrim = Standard_True;
      else
	{
	  Vmin = V1;
	  bVmin = Standard_True;
	}
      
      if (Precision::IsInfinite(V2))
	bIsTrim = Standard_True;
      else
	{
	  Vmax = V2;
	  bVmax = Standard_True;
	}
    }
  else
    {
      BRepTools::UVBounds(aF, U1, U2, V1, V2);
      if (Precision::IsInfinite(U1) &&
	  Precision::IsInfinite(U2) &&
	  Precision::IsInfinite(V1) &&
	  Precision::IsInfinite(V2))
	bIsTrim = Standard_True;
    }

  if (bIsTrim)
    {      
      Bnd_Box aEdgeBox;
      BRepBndLib::Add(aE, aEdgeBox);

      if(aEdgeBox.IsWhole())
	return;

      Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
      aEdgeBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);

      TColStd_Array1OfReal arrU(1, 8);
      TColStd_Array1OfReal arrV(1, 8);
      TColgp_Array1OfPnt arrPnt(1, 8);

      gp_Pnt aPnt1(Xmin, Ymin, Zmin);
      arrPnt.SetValue(1, aPnt1);
      gp_Pnt aPnt2(Xmin, Ymax, Zmin);
      arrPnt.SetValue(2, aPnt2);
      gp_Pnt aPnt3(Xmin, Ymax, Zmax);
      arrPnt.SetValue(3, aPnt3);
      gp_Pnt aPnt4(Xmin, Ymin, Zmax);
      arrPnt.SetValue(4, aPnt4);
      gp_Pnt aPnt5(Xmax, Ymax, Zmin);
      arrPnt.SetValue(5, aPnt5);
      gp_Pnt aPnt6(Xmax, Ymax, Zmax);
      arrPnt.SetValue(6, aPnt6);
      gp_Pnt aPnt7(Xmax, Ymin, Zmax);
      arrPnt.SetValue(7, aPnt7);
      gp_Pnt aPnt8(Xmax, Ymin, Zmin);
      arrPnt.SetValue(8, aPnt8);
      
      Standard_Real U, V;
      Standard_Integer i;
      GeomAPI_ProjectPointOnSurf aProj(aPnt1, pSurf);
      for (i = 1; i <= arrPnt.Length(); i++)
	{
	  gp_Pnt aPnt = arrPnt.Value(i);
	  aProj.Perform(aPnt);
	  if (aProj.IsDone())
	    {
	      aProj.LowerDistanceParameters(U, V);
	      arrU.SetValue(i, U);
	      arrV.SetValue(i, V);	      
	      
	    }
	}

      Standard_Real aU, aV;
      if (!bUmin)
	Umin = arrU.Value(1);
      if (!bUmax)
	Umax = arrU.Value(1);
      if (!bVmin)
	Vmin = arrV.Value(1);
      if (!bVmax)
	Vmax = arrV.Value(1);

      for(i = 1; i <= arrU.Length(); i++)
	{
	  aU = arrU.Value(i);
	  if (aU < Umin)
	    Umin = aU;
	  else if (aU > Umax)
	    Umax = aU;

	  aV = arrV.Value(i);
	  if (aV < Vmin)
	    Vmin = aV;
	  else if (aV > Vmax)
	    Vmax = aV;
	}
      
      GeomAdaptor_Surface aGAS(pSurf);
      Standard_Real tol = BRep_Tool::Tolerance(aF);
      Standard_Real EpsU = aGAS.UResolution(3*tol);
      Standard_Real EpsV = aGAS.VResolution(3*tol);
      if (fabs(Umin - Umax) < EpsU)
	{
	  Umin = Umin - EpsU;
	  Umax = Umax + EpsU;
	}

      if (fabs(Vmin - Vmax) < EpsV)
	{
	  Vmin = Vmin - EpsV;
	  Vmax = Vmax + EpsV;
	}

      Handle(Geom_Surface) result = new Geom_RectangularTrimmedSurface(pSurf, Umin, Umax, Vmin, Vmax);
      aResFace = BRepBuilderAPI_MakeFace(result);
      
      bIsInfinit = Standard_True;
    }
  else
    bIsInfinit = Standard_False;
}

//------------------------------------------------------------------------------
// static function: PERFORM_C0
//------------------------------------------------------------------------------
static void PERFORM_C0(TopoDS_Edge S1, 
		       TopoDS_Edge S2, 
		       BRepExtrema_SeqOfSolution& SeqSol1,
		       BRepExtrema_SeqOfSolution& SeqSol2,
		       Standard_Real DstRef,
		       Standard_Real& mDstRef,
		       const Standard_Real& Eps)
{

  if ( BRep_Tool::Degenerated(S1) ||
      BRep_Tool::Degenerated(S2) )
    return;
  Standard_Integer iE;
//   TopoDS_Edge E, Eover;
  for (iE = 0; iE < 2; iE++)
    {
      TopoDS_Edge E, Eother;
      if (iE == 0)
	{
	  E      = S1;
	  Eother = S2;
	}
      else
	{
	  E      = S2;
	  Eother = S1;
	}
      Standard_Real aFirst, aLast, epsP = Precision::PConfusion(), Udeb, Ufin;
      Handle(Geom_Curve) pCurv = BRep_Tool::Curve(E, aFirst, aLast);
      
      Standard_Real aFOther, aLOther;
      Handle(Geom_Curve) pCurvOther = BRep_Tool::Curve(Eother, aFOther, aLOther);
	


      GeomAbs_Shape s = pCurv->Continuity();
      if (s == GeomAbs_C0)
	{
	  GeomAdaptor_Curve aAdaptorCurve(pCurv, aFirst, aLast);
	  Standard_Integer nbIntervals = aAdaptorCurve.NbIntervals(GeomAbs_C1);
	  
	  TColStd_Array1OfReal arrInter(1,1+nbIntervals);
	  aAdaptorCurve.Intervals(arrInter, GeomAbs_C1);

	  GeomAdaptor_Curve aAdaptorCurveOther(pCurvOther, aFOther, aLOther);
	  Standard_Integer nbIntervalsOther = aAdaptorCurveOther.NbIntervals(GeomAbs_C1);
	  TColStd_Array1OfReal arrInterOther(1,1+nbIntervalsOther);
	  aAdaptorCurveOther.Intervals(arrInterOther, GeomAbs_C1);
	  
	  Standard_Real Dstmin, Dst;
	  gp_Pnt P1,Pt;
	  gp_Pnt2d PUV;
	  Standard_Boolean notavertex, inserer;
	  Standard_Integer i, ii;  
	  BRepClass_FaceClassifier classifier;
	  Standard_Real aParameter;
	  for (i=1; i<=arrInter.Length(); i++)
	    {	
	      gp_Pnt aPnt = aAdaptorCurve.Value(arrInter(i));
	      
	      TopoDS_Vertex V1 = BRepBuilderAPI_MakeVertex(aPnt);
	      
	      aParameter = arrInter(i);
	      BRepExtrema_ExtPC Ext(V1,Eother);
	      if ( (Ext.IsDone()) && (Ext.NbExt() > 0) )
		{ 
		  Standard_Integer NbExtrema=Ext.NbExt();
		  
		  //       Recherche de la distance minimum dstmin
		  Dstmin=sqrt (Ext.SquareDistance(1));
		  for (ii=2;ii<=NbExtrema;ii++)
		    {
		      Dst=sqrt (Ext.SquareDistance(ii));
		      if (Dst<Dstmin) 
			Dstmin=Dst;
		    }

		  if ((Dstmin < DstRef -Eps) || (fabs(Dstmin-DstRef)<Eps))
		    for (ii=1;ii<=NbExtrema;ii++)
		      { if (fabs(Dstmin-sqrt(Ext.SquareDistance(ii)))<Eps)
			  {Pt=Ext.Point(ii);
			   TRI_SOLUTION(SeqSol2,Pt,inserer);
			   if (inserer) 
			     {
			       // on regarde si le parametre ne correspondont pas a un vertex
			       Standard_Real t =Ext.Parameter(ii) ;
			       notavertex=Standard_True;
			       BRep_Tool::Range(Eother,Udeb,Ufin);
			       if ((fabs(t-Udeb)<epsP)||(fabs(t-Ufin)<=epsP )) notavertex=Standard_False;
			       if (notavertex)
				 {
				   //  Modified by Sergey KHROMOV - Tue Mar  6 12:28:51 2001 Begin
				   if (mDstRef > Dstmin)
				     mDstRef=Dstmin;
				   //  Modified by Sergey KHROMOV - Tue Mar  6 12:28:54 2001 End
				   //myModif=Standard_True;
				   P1=BRep_Tool::Pnt(V1);
				   BRepExtrema_SolutionElem Sol1 (Dstmin,P1,BRepExtrema_IsOnEdge,E, aParameter);
				   BRepExtrema_SolutionElem Sol2 (Dstmin,Pt,BRepExtrema_IsOnEdge,Eother,t);
				   SeqSol1.Append(Sol1);
				   SeqSol2.Append(Sol2);		  
				 }
			     }
			 }
		      }
		  
		  
		}
	      Standard_Real aParameterOther;
	      for (Standard_Integer i2 = 1; i2<=arrInterOther.Length(); i2++)
		{
		  gp_Pnt aPntOther = aAdaptorCurveOther.Value(arrInterOther(i2));
		  Dst=aPnt.Distance(aPntOther);
		  aParameterOther = arrInterOther(i2);
		  if( (Dst< DstRef  - Eps ) || (fabs(Dst-DstRef)< Eps ))
		    { 		
		      if (mDstRef > Dst)
			mDstRef=Dst;

		      BRepExtrema_SolutionElem Sol1 (Dst,aPnt,BRepExtrema_IsOnEdge,E, aParameter);
		      BRepExtrema_SolutionElem Sol2 (Dst,aPntOther, BRepExtrema_IsOnEdge,Eother, aParameterOther);
		      SeqSol1.Append(Sol1);
		      SeqSol2.Append(Sol2);
		    }		  

		}
	    }
	  
	  
	}
    }
}

/*********************************************************************************/

BRepExtrema_DistanceSS::BRepExtrema_DistanceSS(const TopoDS_Shape& S1, 
					       const TopoDS_Shape& S2, 
					       const Bnd_Box& B1, 
					       const Bnd_Box& B2, 
					       const Standard_Real DstRef)

{
  myEps = Precision::Confusion();
  Perform(S1, S2, B1, B2, DstRef);
}

/*********************************************************************************/

BRepExtrema_DistanceSS::BRepExtrema_DistanceSS(const TopoDS_Shape& S1, 
					       const TopoDS_Shape& S2, 
					       const Bnd_Box& B1, 
					       const Bnd_Box& B2, 
					       const Standard_Real DstRef,
					       const Standard_Real theDeflection)

{
  myEps = theDeflection;
  Perform(S1, S2, B1, B2, DstRef);
}

/*********************************************************************************/

void BRepExtrema_DistanceSS::Perform(const TopoDS_Shape& S1, 
				     const TopoDS_Shape& S2, 
				     const Bnd_Box& B1, 
				     const Bnd_Box& B2, 
				     const Standard_Real DstRef)
 
{
TopAbs_ShapeEnum       Type1, Type2;
  Type1 = S1.ShapeType();     
  Type2 = S2.ShapeType();
//  Modified by Sergey KHROMOV - Tue Mar  6 12:55:05 2001 Begin
  myDstRef = DstRef;
//  Modified by Sergey KHROMOV - Tue Mar  6 12:55:05 2001 End
  TopoDS_Face aTrimFace;
  TopoDS_Edge aTrimEdge;
  Standard_Boolean bIsInfinit;
  switch ( Type1)
   { case TopAbs_VERTEX :
		  switch (Type2)
		   { case TopAbs_VERTEX : { TopoDS_Vertex V1 = TopoDS::Vertex(S1);
			   	            TopoDS_Vertex V2 = TopoDS::Vertex(S2);
				            Perform  ( V1 , V2, B1, B2,DstRef );}
                                            break; 
  		     case TopAbs_EDGE   : { TopoDS_Vertex V1 = TopoDS::Vertex(S1);
				            TopoDS_Edge V2 = TopoDS::Edge(S2);
				             Perform  ( V1 , V2,  B1, B2,DstRef );}
                                            break; 
		     case TopAbs_FACE   : { TopoDS_Vertex V1 = TopoDS::Vertex(S1);
					    TopoDS_Face V2 = TopoDS::Face(S2);
				            Perform ( V1 , V2, B1, B2,DstRef );}
                                            break; 
		     default :{}           
		     }break;

      case TopAbs_EDGE :
		   switch (Type2)
		    { case TopAbs_VERTEX : { TopoDS_Edge V1 = TopoDS::Edge(S1);
				             TopoDS_Vertex V2 = TopoDS::Vertex(S2);
				             Perform ( V1 , V2, B1, B2,DstRef );} 
                                             break;
  		      case TopAbs_EDGE   : { TopoDS_Edge V1 = TopoDS::Edge(S1);
				             TopoDS_Edge V2 = TopoDS::Edge(S2);
					     Standard_Boolean bIsTrim1 = Standard_False;
					     Standard_Boolean bIsTrim2 = Standard_False;
					     TRIM_INFINIT_EDGE(V1, V2, aTrimEdge, bIsTrim1, bIsTrim2);
					     if (bIsTrim1)
					       V1 = aTrimEdge;
					     if (bIsTrim2)
					       V2 = aTrimEdge;
				             Perform   ( V1 , V2,  B1, B2,DstRef );}
                                             break;
		      case TopAbs_FACE   : { TopoDS_Edge V1 = TopoDS::Edge(S1);
					     TopoDS_Face V2 = TopoDS::Face(S2);					    
					     TRIM_INFINIT_FACE(V1, V2, aTrimFace, bIsInfinit);
					     if (bIsInfinit)
					       V2 = aTrimFace;
				              Perform ( V1 , V2, B1, B2,DstRef  );}
                                              break;
		      default :{}    }break;

      case TopAbs_FACE :
		    switch (Type2)
		      { case TopAbs_VERTEX : { TopoDS_Face V1 = TopoDS::Face(S1);
					       TopoDS_Vertex V2 = TopoDS::Vertex(S2);
					       Perform ( V1 , V2,  B1, B2,DstRef);}
                                               break;
  		        case TopAbs_EDGE   : { TopoDS_Face V1 = TopoDS::Face(S1);
					       TopoDS_Edge V2 = TopoDS::Edge(S2);
					       TRIM_INFINIT_FACE(V1, V2, aTrimFace, bIsInfinit);
					       if (bIsInfinit)
						 V1 = aTrimFace;
					       Perform ( V1 , V2,  B1, B2,DstRef );}
                                                break;
		        case TopAbs_FACE   : { TopoDS_Face V1 = TopoDS::Face(S1);
					       TopoDS_Face V2 = TopoDS::Face(S2);
						Perform( V1 , V2,   B1, B2,DstRef);}
                                               break;
		        default :{}
		        }break;
     default :{}
 }
}

/*********************************************************************************/

void BRepExtrema_DistanceSS::Perform(const TopoDS_Vertex& S1, const TopoDS_Vertex& S2, 
				      const Bnd_Box& ,
//                                      const Bnd_Box& B2, 
                                      const Bnd_Box& , 
				      const Standard_Real DstRef)
{     
   gp_Pnt P1,P2;
   Standard_Real Dst;
   P1= BRep_Tool::Pnt(S1);
   P2= BRep_Tool::Pnt(S2); 
   Dst=P1.Distance(P2);  
   SeqSolShape1.Clear();
   SeqSolShape2.Clear();
   myModif=Standard_False;
   
   if( (Dst< DstRef  -myEps ) || (fabs(Dst-DstRef)< myEps ))      
   { 
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:51 2001 Begin
     if (myDstRef > Dst)
       myDstRef=Dst;
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:54 2001 End
     myModif=Standard_True;
     BRepExtrema_SolutionElem Sol1 (Dst,P1,BRepExtrema_IsVertex,S1);
     BRepExtrema_SolutionElem Sol2 (Dst,P2, BRepExtrema_IsVertex,S2);
     SeqSolShape1.Append(Sol1);
     SeqSolShape2.Append(Sol2);
   }
}

/*********************************************************************************/

void BRepExtrema_DistanceSS::Perform(const TopoDS_Vertex& S1, const TopoDS_Edge& S2, 
				      const Bnd_Box& B1, const Bnd_Box& B2, 
				      const Standard_Real DstRef)
{ 
   Standard_Real Dst,Dstmin,epsP,Udeb,Ufin ; 
   gp_Pnt Pt,P1;
   Standard_Boolean inserer,notavertex;
   Standard_Integer i;  
   
   epsP=Precision::PConfusion();
   SeqSolShape1.Clear();
   SeqSolShape2.Clear();
   myModif=Standard_False;
 
  
   if (!BRep_Tool::Degenerated (S2)) {
   Dst=B1.Distance(B2);
   if ( (Dst< DstRef  -myEps ) || (fabs(Dst-DstRef)< myEps ))     
   { 
     BRepExtrema_ExtPC Ext(S1,S2); 
     if ( (Ext.IsDone()) && (Ext.NbExt() > 0) )
       { Standard_Integer NbExtrema=Ext.NbExt();
//       Recherche de la distance minimum dstmin
         Dstmin=sqrt(Ext.SquareDistance(1));
         for (i=2;i<=NbExtrema;i++)
	   {Dst=sqrt(Ext.SquareDistance(i));
            if (Dst<Dstmin) 
               Dstmin=Dst;
	    }
         if ((Dstmin < DstRef -myEps) || (fabs(Dstmin-DstRef)<myEps))
         for (i=1;i<=NbExtrema;i++)
	   { if (fabs(Dstmin-sqrt(Ext.SquareDistance(i)))<myEps)
		     {Pt=Ext.Point(i);
                      TRI_SOLUTION(SeqSolShape2,Pt,inserer);
                      if (inserer) 
			 {
                          // on regarde si le parametre ne correspondont pas a un vertex
                          Standard_Real t =Ext.Parameter(i) ;
                          notavertex=Standard_True;
                          BRep_Tool::Range(S2,Udeb,Ufin);
                          if ((fabs(t-Udeb)<epsP)||(fabs(t-Ufin)<=epsP )) notavertex=Standard_False;
                          if (notavertex)
                          {
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:51 2001 Begin
			   if (myDstRef > Dstmin)
			     myDstRef=Dstmin;
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:54 2001 End
                           myModif=Standard_True;
                           P1=BRep_Tool::Pnt(S1);
                           BRepExtrema_SolutionElem Sol1 (Dstmin,P1,BRepExtrema_IsVertex,S1);
                           BRepExtrema_SolutionElem Sol2 (Dstmin,Pt,BRepExtrema_IsOnEdge,S2,t);
                           SeqSolShape1.Append(Sol1);
                           SeqSolShape2.Append(Sol2);		  
                          }
                        }
                    }
	   }
   }
   }
}
}

/*********************************************************************************/

void BRepExtrema_DistanceSS::Perform(const TopoDS_Vertex& S1, const TopoDS_Face& S2, 
				      const Bnd_Box& B1, const Bnd_Box& B2,
				      const Standard_Real DstRef)
{
   Standard_Real Dst,Dstmin,epsP,U,V ; 
   gp_Pnt P1,Pt;
   gp_Pnt2d PUV;
   Standard_Boolean inserer,notavertex;
   Standard_Integer i;  
   BRepClass_FaceClassifier classifier; 
   
   epsP=Precision::PConfusion();
   SeqSolShape1.Clear();
   SeqSolShape2.Clear();
   myModif=Standard_False;
 

   Dst=B1.Distance(B2);
   if ( (Dst< DstRef  -myEps ) || (fabs(Dst-DstRef)< myEps ))     
   { 
     BRepExtrema_ExtPF Ext(S1,S2);
     if ( (Ext.IsDone()) && (Ext.NbExt() > 0) )
       { Standard_Integer NbExtrema=Ext.NbExt();
//       Recherche de la distance minimum dstmin
         Dstmin=sqrt(Ext.SquareDistance(1));
         for (i=2;i<=NbExtrema;i++)
	   {Dst=sqrt (Ext.SquareDistance(i));
            if (Dst<Dstmin) 
               Dstmin=Dst;
	    }
         if ((Dstmin < DstRef -myEps) || (fabs(Dstmin-DstRef)<myEps))
         for (i=1;i<=NbExtrema;i++)
	   { if (fabs(Dstmin-sqrt(Ext.SquareDistance(i)))<myEps)
		     { Pt=Ext.Point(i);
                      TRI_SOLUTION(SeqSolShape2,Pt,inserer);
                      if (inserer) 
			 {
                          // on regarde si le parametre ne correspondont pas a un vertex
                          Ext.Parameter(i,U,V);
  
                          PUV.SetCoord(U,V);
		          Standard_Real tol=BRep_Tool::Tolerance(S2);
                          classifier.Perform(S2,PUV,tol);
                          notavertex=(classifier.State()==TopAbs_IN); 
                          if (notavertex)
                          {
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:51 2001 Begin
			   if (myDstRef > Dstmin)
			     myDstRef=Dstmin;
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:54 2001 End
                           myModif=Standard_True;
                           P1=BRep_Tool::Pnt(S1);
                           BRepExtrema_SolutionElem Sol1 (Dstmin,P1,BRepExtrema_IsVertex,S1);
                           BRepExtrema_SolutionElem Sol2 (Dstmin,Pt,BRepExtrema_IsInFace,S2,U,V);
                           SeqSolShape1.Append(Sol1);
                           SeqSolShape2.Append(Sol2);		  
                          }
                        }
                    }
	   }
   }
   }
}

/*********************************************************************************/

void BRepExtrema_DistanceSS::Perform(const TopoDS_Edge& S1, const TopoDS_Vertex& S2, 
				      const Bnd_Box& B1, const Bnd_Box& B2, 
				      const Standard_Real DstRef)

{Standard_Real Dst,Dstmin,epsP,Udeb,Ufin ; 
   gp_Pnt Pt,P1;
   Standard_Boolean inserer,notavertex;
   Standard_Integer i;  
   
   epsP=Precision::PConfusion();
   SeqSolShape1.Clear();
   SeqSolShape2.Clear();
   myModif=Standard_False;
   
   if (!BRep_Tool::Degenerated(S1))  {
   Dst=B1.Distance(B2);
   if ( (Dst< DstRef  -myEps ) || (fabs(Dst-DstRef)< myEps ))     
   { 
     BRepExtrema_ExtPC Ext(S2,S1);
     if ( (Ext.IsDone()) && (Ext.NbExt() > 0) )
       { Standard_Integer NbExtrema=Ext.NbExt();
//       Recherche de la distance minimum dstmin
         Dstmin=sqrt(Ext.SquareDistance(1));
         for (i=2;i<=NbExtrema;i++)

	   {Dst=sqrt(Ext.SquareDistance(i));
            if (Dst<Dstmin) 
               Dstmin=Dst;
	    }
         if ((Dstmin < DstRef -myEps) || (fabs(Dstmin-DstRef)<myEps))
         for (i=1;i<=NbExtrema;i++)
	   { if (fabs(Dstmin-sqrt (Ext.SquareDistance(i)))<myEps)
		     {Pt=Ext.Point(i);
                      TRI_SOLUTION(SeqSolShape1,Pt,inserer); 
                      if (inserer) 
			 {
                          // on regarde si le parametre ne correspondont pas a un vertex
                          Standard_Real t =Ext.Parameter(i) ;
                          notavertex=Standard_True;
                          BRep_Tool::Range(S1,Udeb,Ufin);
                          if ((fabs(t-Udeb)<epsP)||(fabs(t-Ufin)<=epsP )) notavertex=Standard_False;
                          if (notavertex)
                          {
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:51 2001 Begin
			   if (myDstRef > Dstmin)
			     myDstRef=Dstmin;
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:54 2001 End
                           myModif=Standard_True;
                           P1=BRep_Tool::Pnt(S2);
                           BRepExtrema_SolutionElem Sol1 (Dstmin,Pt,BRepExtrema_IsOnEdge,S1,t);
                           BRepExtrema_SolutionElem Sol2 (Dstmin,P1,BRepExtrema_IsVertex,S2);
                           SeqSolShape1.Append(Sol1);
                           SeqSolShape2.Append(Sol2);
                          }
                        }
                    }
	   }
   }
   }
}
}

/*********************************************************************************/

void BRepExtrema_DistanceSS::Perform(const TopoDS_Edge& S1, const TopoDS_Edge& S2, 
				      const Bnd_Box& B1, const Bnd_Box& B2, 
				      const Standard_Real DstRef)

{
   Standard_Real Dst,Dstmin,epsP,Udeb,Ufin; 
   gp_Pnt Pt1,Pt2;
   Standard_Boolean insere1, insere2, notavertex;
   Standard_Integer i;   
   
   epsP=Precision::PConfusion();
   SeqSolShape1.Clear();
   SeqSolShape2.Clear();
   myModif=Standard_False;
   
   if (!BRep_Tool::Degenerated(S1)&& !BRep_Tool::Degenerated(S2))

 {

   Dst=B1.Distance(B2);
   if ( (Dst< DstRef  -myEps ) || (fabs(Dst-DstRef)< myEps ))     
   { 
     BRepExtrema_ExtCC Ext(S1,S2);
     if ( (Ext.IsDone()) && (Ext.NbExt() > 0) && (!Ext.IsParallel())) 
       { Standard_Integer NbExtrema=Ext.NbExt();
//       Recherche de la distance minimum dstmin
         Dstmin=sqrt (Ext.SquareDistance(1));
         for (i=2;i<=NbExtrema;i++)
	   {Dst=sqrt (Ext.SquareDistance(i));
            if (Dst<Dstmin) 
               Dstmin=Dst;
	  }
	 if ((Dstmin < DstRef -myEps) || (fabs(Dstmin-DstRef)<myEps))   
         for (i=1;i<=NbExtrema;i++)
	   { if (fabs(Dstmin-sqrt (Ext.SquareDistance(i)))<myEps )
		     {Pt1=Ext.PointOnE1(i);
                      Pt2=Ext.PointOnE2(i);
                      TRI_SOLUTION(SeqSolShape1,Pt1,insere1);
                      TRI_SOLUTION(SeqSolShape2,Pt2,insere2);
                      if (insere1 ||insere2 ) 
			 {
                          // on regarde si le parametre ne correspondont pas a un vertex
                          Standard_Real t1 =Ext.ParameterOnE1(i) ;
                          Standard_Real t2 =Ext.ParameterOnE2(i) ;
                          
                          notavertex=Standard_True;
                          BRep_Tool::Range(S1,Udeb,Ufin);
                          if ((fabs(t1-Udeb)<epsP)||(fabs(t1-Ufin)<=epsP )) notavertex=Standard_False;
                           
                          BRep_Tool::Range(S2,Udeb,Ufin);
                          if ((fabs(t2-Udeb)<epsP)||(fabs(t2-Ufin)<=epsP )) notavertex=Standard_False;
  
                          if (notavertex)
                          {
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:51 2001 Begin
			   if (myDstRef > Dstmin)
			     myDstRef=Dstmin;
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:54 2001 End
                           myModif=Standard_True;
                           BRepExtrema_SolutionElem Sol1 (Dstmin,Pt1,BRepExtrema_IsOnEdge,S1,t1);
                           BRepExtrema_SolutionElem Sol2 (Dstmin,Pt2,BRepExtrema_IsOnEdge,S2,t2);
                           SeqSolShape1.Append(Sol1);
                           SeqSolShape2.Append(Sol2);
                          }
                        }
                
    }
	   }
   }

     BRepExtrema_SeqOfSolution SeqSolution1;
     BRepExtrema_SeqOfSolution SeqSolution2;
//      Standard_Integer i;

     PERFORM_C0(S1, S2, SeqSolution1, SeqSolution2, DstRef, myDstRef, myEps);
     
     BRepExtrema_SeqOfSolution seqSol1;
     BRepExtrema_SeqOfSolution seqSol2;
	
     if (SeqSolution1.Length() > 0 && SeqSolution2.Length() > 0) {
       MIN_SOLUTION(SeqSolution1, SeqSolution2, myDstRef, myEps, seqSol1, seqSol2);
     }
     
     if (!seqSol1.IsEmpty() && !seqSol2.IsEmpty())
       {
	 SeqSolShape1.Append(seqSol1);
	 SeqSolShape2.Append(seqSol2);	
	 myModif = Standard_True;
       }
     
   }
 }
 }

/*********************************************************************************/

void BRepExtrema_DistanceSS::Perform(const TopoDS_Edge& S1, const TopoDS_Face& S2, 
				      const Bnd_Box& B1, const Bnd_Box& B2, 
				      const Standard_Real DstRef)
{
  Standard_Real Dst,Dstmin,epsP,Udeb,Ufin,U,V ; 
  gp_Pnt Pt1,Pt2;
  gp_Pnt2d PUV;
  Standard_Boolean insere1 ,insere2, notavertex;
  BRepClass_FaceClassifier classifier;
  Standard_Integer i;  
  
  epsP=Precision::PConfusion();
  SeqSolShape1.Clear();
  SeqSolShape2.Clear();
  myModif=Standard_False;
  
  if (!BRep_Tool::Degenerated(S1)) {
    
    Dst=B1.Distance(B2);
    if ( (Dst< DstRef  -myEps ) || (fabs(Dst-DstRef)< myEps ))     
      {
	BRepExtrema_ExtCF Ext(S1,S2);
	if ( (Ext.IsDone()) && ((Ext.NbExt() > 0) && (!Ext.IsParallel()) ))
	  { Standard_Integer NbExtrema=Ext.NbExt();
	    //       Recherche de la distance minimum dstmin
	    Dstmin=sqrt (Ext.SquareDistance(1));
	    for (i=2;i<=NbExtrema;i++)
	      {Dst=sqrt (Ext.SquareDistance(i));
	       if (Dst<Dstmin) 
		 Dstmin=Dst;
	     }
	    if ((Dstmin < DstRef -myEps) || (fabs(Dstmin-DstRef)<myEps))
	      for (i=1;i<=NbExtrema;i++)
		{ if (fabs(Dstmin-sqrt (Ext.SquareDistance(i)))<myEps)
		    {Pt1=Ext.PointOnEdge(i);
		     Pt2=Ext.PointOnFace(i);
		     TRI_SOLUTION (SeqSolShape1,Pt1,insere1);
		     TRI_SOLUTION (SeqSolShape2,Pt2,insere2); 
		     if (insere1||insere2)
		       {
			 // on regarde si le parametre ne correspondont pas a un vertex
			 Standard_Real t1 =Ext.ParameterOnEdge(i) ;
			 
			 notavertex=Standard_True;
			 BRep_Tool::Range(S1,Udeb,Ufin);
			 if ((fabs(t1-Udeb)<epsP)||(fabs(t1-Ufin)<=epsP )) notavertex=Standard_False;
			 
			 Ext.ParameterOnFace(i,U,V);
			 PUV.SetCoord(U,V);
			 Standard_Real tol=BRep_Tool::Tolerance(S2);
			 classifier.Perform(S2,PUV,tol);
			 if ( classifier.State()!=TopAbs_IN)  notavertex=Standard_False;
			 
			 if (notavertex)
			   {
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:51 2001 Begin
			     if (myDstRef > Dstmin)
			       myDstRef=Dstmin;
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:54 2001 End
			     myModif=Standard_True;
			     BRepExtrema_SolutionElem Sol1 (Dstmin,Pt1,BRepExtrema_IsOnEdge,S1,t1);
			     BRepExtrema_SolutionElem Sol2 (Dstmin,Pt2,BRepExtrema_IsInFace,S2,U,V);
			     SeqSolShape1.Append(Sol1);
			     SeqSolShape2.Append(Sol2);		  
			   }
		       }
		   }
		}
	  }
	Standard_Real aFirst, aLast;
	Handle(Geom_Curve) pCurv = BRep_Tool::Curve(S1, aFirst, aLast);
	GeomAbs_Shape s = pCurv->Continuity();
	if (s == GeomAbs_C0)
	  {
	    BRepExtrema_SeqOfSolution SeqSolution1;
	    BRepExtrema_SeqOfSolution SeqSolution2;

	    
	    GeomAdaptor_Curve aAdaptorCurve(pCurv, aFirst, aLast);
	    Standard_Integer nbIntervals = aAdaptorCurve.NbIntervals(GeomAbs_C1);
	    
	    TColStd_Array1OfReal arrInter(1,1+nbIntervals);
	    aAdaptorCurve.Intervals(arrInter, GeomAbs_C1);
	    
// 	    Standard_Real U,V;
	    gp_Pnt P1,Pt;
// 	    gp_Pnt2d PUV;
// 	    Standard_Boolean notavertex;
// 	    Standard_Integer i, ii;  
	    Standard_Integer ii;  
// 	    BRepClass_FaceClassifier classifier;
	    Standard_Real aParameter;
	    for (i=1; i<=arrInter.Length(); i++)
	      {	
		gp_Pnt aPnt = aAdaptorCurve.Value(arrInter(i));
		
		TopoDS_Vertex V1 = BRepBuilderAPI_MakeVertex(aPnt);

		aParameter = arrInter(i);
		
		BRepExtrema_ExtPF ExtPF(V1,S2);
		if ( (ExtPF.IsDone()) && (ExtPF.NbExt() > 0) )
		  { 
		    Standard_Integer NbExtrema=ExtPF.NbExt();
		    //       Recherche de la distance minimum dstmin
		    Dstmin=sqrt (ExtPF.SquareDistance(1));
		    for (ii=2;ii<=NbExtrema;ii++)
		      {Dst=sqrt(ExtPF.SquareDistance(ii));
		       if (Dst<Dstmin) 
			 Dstmin=Dst;
		     }
		    if ((Dstmin < DstRef -myEps) || (fabs(Dstmin-DstRef)<myEps))
		      {
			
			for (ii=1;ii<=NbExtrema;ii++)
			  { 
			    if (fabs(Dstmin-sqrt (ExtPF.SquareDistance(ii)))<myEps)
			      { 
				Pt=ExtPF.Point(ii);
				// on regarde si le parametre ne correspondont pas a un vertex
				ExtPF.Parameter(ii,U,V);
				// Standard_Real t1 =Ext.ParameterOnEdge(ii) ;
								
				PUV.SetCoord(U,V);
				Standard_Real tol=BRep_Tool::Tolerance(S2);
				classifier.Perform(S2,PUV,tol);
				notavertex=(classifier.State()==TopAbs_IN); 
				if (notavertex)
				  {
				    //  Modified by Sergey KHROMOV - Tue Mar  6 12:28:51 2001 Begin
				    if (myDstRef > Dstmin)
				      myDstRef=Dstmin;
				    //  Modified by Sergey KHROMOV - Tue Mar  6 12:28:54 2001 End
				    myModif=Standard_True;
				    P1=BRep_Tool::Pnt(V1);
				    BRepExtrema_SolutionElem Sol1 (Dstmin,P1,BRepExtrema_IsOnEdge,S1,aParameter);
				    BRepExtrema_SolutionElem Sol2 (Dstmin,Pt,BRepExtrema_IsInFace,S2,U,V);
				    SeqSolution1.Append(Sol1);
				    SeqSolution2.Append(Sol2);
				  }
			      }
			  }
		      }
		  }
	      }
	    BRepExtrema_SeqOfSolution seqSol1;
	    BRepExtrema_SeqOfSolution seqSol2;
	    Standard_Boolean bIsMini = Standard_False;
	    if (SeqSolution1.Length() > 0 && SeqSolution2.Length() > 0)
	      MIN_SOLUTION(SeqSolution1, SeqSolution2, myDstRef, myEps, seqSol1, seqSol2);
	    
	    if (!seqSol1.IsEmpty() && !seqSol2.IsEmpty())
	      {
		SeqSolShape1.Append(seqSol1);
		SeqSolShape2.Append(seqSol2);
	      }
	  }
      }
  }
}

/*********************************************************************************/

void BRepExtrema_DistanceSS::Perform(const TopoDS_Face& S1, const TopoDS_Vertex& S2, 
				      const Bnd_Box& B1, const Bnd_Box& B2, 
				      const Standard_Real DstRef)

{
   Standard_Real Dst,Dstmin,epsP,U,V ; 
   gp_Pnt P1,Pt;
   gp_Pnt2d PUV;
   Standard_Boolean inserer,notavertex;
   Standard_Integer i;  
   BRepClass_FaceClassifier classifier; 
   
   epsP=Precision::PConfusion();
   SeqSolShape1.Clear();
   SeqSolShape2.Clear();
   myModif=Standard_False;

   Dst=B1.Distance(B2);
   if ( (Dst< DstRef  -myEps ) || (fabs(Dst-DstRef)< myEps ))     
   { 
     BRepExtrema_ExtPF Ext(S2,S1);
    
     if ( (Ext.IsDone()) && (Ext.NbExt() > 0) )
       { Standard_Integer NbExtrema=Ext.NbExt();
//       Recherche de la distance minimum dstmin
         Dstmin=sqrt(Ext.SquareDistance(1));
         for (i=2;i<=NbExtrema;i++)
	   {Dst=sqrt(Ext.SquareDistance(i));
            if (Dst<Dstmin) 
               Dstmin=Dst;
	    }
         if ((Dstmin < DstRef -myEps) || (fabs(Dstmin-DstRef)<myEps))
         for (i=1;i<=NbExtrema;i++)
	   { if (fabs(Dstmin-sqrt (Ext.SquareDistance(i)))<myEps)
		     {Pt=Ext.Point(i);
                      TRI_SOLUTION (SeqSolShape1,Pt,inserer);
                      if (inserer) 
			 {
                          // on regarde si le parametre ne correspondont pas a un vertex
                          Ext.Parameter(i,U,V);
               
                          PUV.SetCoord(U,V);
		          Standard_Real tol=BRep_Tool::Tolerance(S1);
                          classifier.Perform(S1,PUV,tol);
                          notavertex=(classifier.State()==TopAbs_IN); 
                          if (notavertex)
                          {
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:51 2001 Begin
			   if (myDstRef > Dstmin)
			     myDstRef=Dstmin;
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:54 2001 End
                           myModif=Standard_True;
                           P1=BRep_Tool::Pnt(S2);
                           BRepExtrema_SolutionElem Sol1 (Dstmin,Pt,BRepExtrema_IsInFace,S1,U,V);
                           BRepExtrema_SolutionElem Sol2 (Dstmin,P1,BRepExtrema_IsVertex,S2);
                           SeqSolShape1.Append(Sol1);
                           SeqSolShape2.Append(Sol2);		  
                          }
                        }
                    }
	   }
   }
   }
}

/*********************************************************************************/

void BRepExtrema_DistanceSS::Perform(const TopoDS_Face& S1, const TopoDS_Edge& S2, 
				      const Bnd_Box& B1, const Bnd_Box& B2, 
				      const Standard_Real DstRef)

{
   Standard_Real Dst,Dstmin,epsP,Udeb,Ufin,U,V ; 
   gp_Pnt Pt1,Pt2;
   gp_Pnt2d PUV;
   Standard_Boolean insere1,insere2,notavertex;
   BRepClass_FaceClassifier classifier;
   Standard_Integer i;  
   
   epsP=Precision::PConfusion();
   SeqSolShape1.Clear();
   SeqSolShape2.Clear();
   myModif=Standard_False;
   
   if (!BRep_Tool::Degenerated(S2)) 
  {
   Dst=B1.Distance(B2);
   if ( (Dst< DstRef  -myEps ) || (fabs(Dst-DstRef)< myEps ))     
   { 
     BRepExtrema_ExtCF Ext(S2,S1);
     if ( (Ext.IsDone()) && ((Ext.NbExt() > 0) && (!Ext.IsParallel())) )
         { Standard_Integer NbExtrema=Ext.NbExt();
//       Recherche de la distance minimum dstmin
         Dstmin=sqrt (Ext.SquareDistance(1));
         for (i=2;i<=NbExtrema;i++)
	   {Dst=sqrt (Ext.SquareDistance(i));
            if (Dst<Dstmin) 
               Dstmin=Dst;}
	  if ((Dstmin < DstRef -myEps) || (fabs(Dstmin-DstRef)<myEps))   
         for (i=1;i<=NbExtrema;i++)
	   { if (fabs(Dstmin-sqrt (Ext.SquareDistance(i)))<myEps)
		     {Pt1=Ext.PointOnFace(i);
                      Pt2=Ext.PointOnEdge(i);
                      TRI_SOLUTION (SeqSolShape1,Pt1,insere1);
                      TRI_SOLUTION (SeqSolShape2,Pt2,insere2); 
                      if (insere1||insere2)
          
			 {
                          // on regarde si le parametre ne correspondont pas a un vertex
                          Standard_Real t1 =Ext.ParameterOnEdge(i) ;
                          
                          notavertex=Standard_True;
                          BRep_Tool::Range(S2,Udeb,Ufin);
                          if ((fabs(t1-Udeb)<epsP)||(fabs(t1-Ufin)<=epsP )) notavertex=Standard_False;
                    
                          Ext.ParameterOnFace(i,U,V);
                          PUV.SetCoord(U,V);
		          Standard_Real tol=BRep_Tool::Tolerance(S1);
                          classifier.Perform(S1,PUV,tol);
                          if (classifier.State()!=TopAbs_IN) notavertex=Standard_False; 
                
                          if (notavertex)
                          {
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:51 2001 Begin
			   if (myDstRef > Dstmin)
			     myDstRef=Dstmin;
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:54 2001 End
                           myModif=Standard_True;
                           BRepExtrema_SolutionElem Sol1 (Dstmin,Pt1,BRepExtrema_IsInFace,S1,U,V);
                           BRepExtrema_SolutionElem Sol2 (Dstmin,Pt2,BRepExtrema_IsOnEdge,S2,t1);
                           SeqSolShape1.Append(Sol1);
                           SeqSolShape2.Append(Sol2);		  
                          }
                        }
                    }
	   }
	 }

     Standard_Real aFirst, aLast;
     Handle(Geom_Curve) pCurv = BRep_Tool::Curve(S2, aFirst, aLast);
     GeomAbs_Shape s = pCurv->Continuity();
     if (s == GeomAbs_C0)
       {
	 BRepExtrema_SeqOfSolution SeqSolution1;
	 BRepExtrema_SeqOfSolution SeqSolution2;


	 GeomAdaptor_Curve aAdaptorCurve(pCurv, aFirst, aLast);
	 Standard_Integer nbIntervals = aAdaptorCurve.NbIntervals(GeomAbs_C1);
	 
	 TColStd_Array1OfReal arrInter(1,1+nbIntervals);
	 aAdaptorCurve.Intervals(arrInter, GeomAbs_C1);
	 
// 	 Standard_Real U,V;
	 gp_Pnt P1,Pt;
// 	 gp_Pnt2d PUV;
// 	 Standard_Boolean notavertex;
	 Standard_Integer ii;  
//	 BRepClass_FaceClassifier classifier;
	 Standard_Real aParameter;
	 for (i=1; i<=arrInter.Length(); i++)
	   {	
	     gp_Pnt aPnt = aAdaptorCurve.Value(arrInter(i));
	     
	     TopoDS_Vertex V1 = BRepBuilderAPI_MakeVertex(aPnt);
	     
	     aParameter = arrInter(i);
	     
	     BRepExtrema_ExtPF ExtPF(V1,S1);
	     if ( (ExtPF.IsDone()) && (ExtPF.NbExt() > 0) )
	       { 
		 Standard_Integer NbExtrema=ExtPF.NbExt();
		 //       Recherche de la distance minimum dstmin
		 Dstmin=sqrt(ExtPF.SquareDistance(1));
		 for (ii=2;ii<=NbExtrema;ii++)
		   {Dst=sqrt(ExtPF.SquareDistance(ii));
		    if (Dst<Dstmin) 
		      Dstmin=Dst;
		  }
		 if ((Dstmin < DstRef -myEps) || (fabs(Dstmin-DstRef)<myEps))
		   {
		     
		     for (ii=1;ii<=NbExtrema;ii++)
		       { 
			 if (fabs(Dstmin-sqrt(ExtPF.SquareDistance(ii)))<myEps)
			   { 
			     Pt=ExtPF.Point(ii);
			     // on regarde si le parametre ne correspondont pas a un vertex
			     ExtPF.Parameter(ii,U,V);
			     // Standard_Real t1 =Ext.ParameterOnEdge(ii) ;
			     
			     PUV.SetCoord(U,V);
			     Standard_Real tol=BRep_Tool::Tolerance(S1);
			     classifier.Perform(S1,PUV,tol);
			     notavertex=(classifier.State()==TopAbs_IN); 
			     if (notavertex)
			       {
				 //  Modified by Sergey KHROMOV - Tue Mar  6 12:28:51 2001 Begin
				 if (myDstRef > Dstmin)
				   myDstRef=Dstmin;
				 //  Modified by Sergey KHROMOV - Tue Mar  6 12:28:54 2001 End
				 myModif=Standard_True;
				 P1=BRep_Tool::Pnt(V1);				 
				 BRepExtrema_SolutionElem Sol1 (Dstmin,Pt,BRepExtrema_IsInFace,S1,U,V);
				 BRepExtrema_SolutionElem Sol2 (Dstmin,P1,BRepExtrema_IsOnEdge,S2,aParameter);
				 SeqSolution1.Append(Sol1);
				 SeqSolution2.Append(Sol2);				 
			       }
			   }
		       }
		   }
	       }
	   }
	 BRepExtrema_SeqOfSolution seqSol1;
	 BRepExtrema_SeqOfSolution seqSol2;
	 Standard_Boolean bIsMini = Standard_False;
	 if (SeqSolution1.Length() > 0 && SeqSolution2.Length() > 0)
	   MIN_SOLUTION(SeqSolution1, SeqSolution2, myDstRef, myEps, seqSol1, seqSol2);
	 
	 if (!seqSol1.IsEmpty() && !seqSol2.IsEmpty())
	   {
	     SeqSolShape1.Append(seqSol1);
	     SeqSolShape2.Append(seqSol2);
	   }
       }
     
   }
 }
 }

/*********************************************************************************/

void BRepExtrema_DistanceSS::Perform(const TopoDS_Face& S1, const TopoDS_Face& S2, 
				      const Bnd_Box& B1, const Bnd_Box& B2, 
				      const Standard_Real DstRef)

{
   Standard_Real Dst,Dstmin,epsP,U1,V1,U2,V2,tol ; 
   gp_Pnt Pt1,Pt2;
   gp_Pnt2d PUV;
   Standard_Boolean insere1,insere2,notavertex;
   BRepClass_FaceClassifier classifier;
   Standard_Integer i;  
   
   epsP=Precision::PConfusion();
   SeqSolShape1.Clear();
   SeqSolShape2.Clear();
   myModif=Standard_False;
 
   Dst=B1.Distance(B2);
   if ( (Dst< DstRef  -myEps ) || (fabs(Dst-DstRef)< myEps ))     
   { 
     BRepExtrema_ExtFF Ext(S1,S2);
     if ( (Ext.IsDone()) && ((Ext.NbExt() > 0) && (!Ext.IsParallel()) ))
       { Standard_Integer NbExtrema=Ext.NbExt();
//       Recherche de la distance minimum dstmin
         Dstmin=sqrt (Ext.SquareDistance(1));
         for (i=2;i<=NbExtrema;i++)
	   {Dst=sqrt(Ext.SquareDistance(i));
            if (Dst<Dstmin) 
               Dstmin=Dst;
	    }
         if ((Dstmin < DstRef -myEps) || (fabs(Dstmin-DstRef)<myEps))
         for (i=1;i<=NbExtrema;i++)
	   { if (fabs(Dstmin-sqrt (Ext.SquareDistance(i)))<myEps)
		     {Pt1=Ext.PointOnFace1(i);
                      Pt2=Ext.PointOnFace2(i); 
                      TRI_SOLUTION (SeqSolShape1,Pt1,insere1);
                      TRI_SOLUTION (SeqSolShape2,Pt2,insere2) ;                             
                         if (insere1||insere2)
			 {
                          // on regarde si le parametre ne correspondont pas a un vertex
              

                    
                          Ext.ParameterOnFace1(i,U1,V1);
                          PUV.SetCoord(U1,V1);
		          tol=BRep_Tool::Tolerance(S1);
                          classifier.Perform(S1,PUV,tol);
                          notavertex=(classifier.State()==TopAbs_IN);
  
                          Ext.ParameterOnFace2(i,U2,V2);
                          PUV.SetCoord(U2,V2);
		          tol=BRep_Tool::Tolerance(S2);
                          classifier.Perform(S2,PUV,tol);
                          if (classifier.State()!=TopAbs_IN) notavertex= Standard_False;
                          
                          if (notavertex)
                          {
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:51 2001 Begin
			   if (myDstRef > Dstmin)
			     myDstRef=Dstmin;
//  Modified by Sergey KHROMOV - Tue Mar  6 12:28:54 2001 End
                           myModif=Standard_True;
                           BRepExtrema_SolutionElem Sol1 (Dstmin,Pt1,BRepExtrema_IsInFace,S1,U1,V1);
                           BRepExtrema_SolutionElem Sol2 (Dstmin,Pt2,BRepExtrema_IsInFace,S2,U2,V2);
                           SeqSolShape1.Append(Sol1);
                           SeqSolShape2.Append(Sol2);		  
                          }
                        }
                    }
	   }
   }
   }
}

/*********************************************************************************/

Standard_Boolean BRepExtrema_DistanceSS::IsDone() const 
{
  return myModif;
}

/*********************************************************************************/

Standard_Real BRepExtrema_DistanceSS::DistValue() const 
{
 return myDstRef;
}

/*********************************************************************************/

const BRepExtrema_SeqOfSolution& BRepExtrema_DistanceSS::Seq1Value() const 
{
 return  SeqSolShape1;
}

/*********************************************************************************/

const BRepExtrema_SeqOfSolution& BRepExtrema_DistanceSS::Seq2Value() const 
{ 
return  SeqSolShape2; 
}

/*********************************************************************************/
/*********************************************************************************/
