// File:	GeomAPI_ExtremaSurfaceSurface.cxx
// Created:	Fri Mar 18 15:58:29 1994
// Author:	Bruno DUMORTIER
//		<dub@fuegox>

#include <GeomAPI_ExtremaSurfaceSurface.ixx>


#include <GeomAdaptor_Surface.hxx>
#include <Extrema_POnSurf.hxx>

#include <Precision.hxx>



//=======================================================================
//function : GeomAPI_ExtremaSurfaceSurface
//purpose  : 
//=======================================================================

GeomAPI_ExtremaSurfaceSurface::GeomAPI_ExtremaSurfaceSurface()
{
  myIsDone = Standard_False;
}


//=======================================================================
//function : GeomAPI_ExtremaSurfaceSurface
//purpose  : 
//=======================================================================

GeomAPI_ExtremaSurfaceSurface::GeomAPI_ExtremaSurfaceSurface
  (const Handle(Geom_Surface)& S1,
   const Handle(Geom_Surface)& S2)
{
  Init(S1,S2);
}


//=======================================================================
//function : GeomAPI_ExtremaSurfaceSurface
//purpose  : 
//=======================================================================

GeomAPI_ExtremaSurfaceSurface::GeomAPI_ExtremaSurfaceSurface
  (const Handle(Geom_Surface)& S1,
   const Handle(Geom_Surface)& S2,
   const Standard_Real         U1min,
   const Standard_Real         U1max,
   const Standard_Real         V1min,
   const Standard_Real         V1max,
   const Standard_Real         U2min,
   const Standard_Real         U2max,
   const Standard_Real         V2min,
   const Standard_Real         V2max)
{
  Init(S1,S2,U1min,U1max,V1min,V1max,U2min,U2max,V2min,V2max);
}


//=======================================================================
//function : Init
//purpose  : 
//=======================================================================

void GeomAPI_ExtremaSurfaceSurface::Init
  (const Handle(Geom_Surface)& S1,
   const Handle(Geom_Surface)& S2)
{
  GeomAdaptor_Surface TheSurface1 (S1);
  GeomAdaptor_Surface TheSurface2 (S2);

  Standard_Real Tol = Precision::PConfusion();
  
  Extrema_ExtSS theExtSS(TheSurface1, TheSurface2,Tol,Tol);
  myExtSS = theExtSS;

  myIsDone = myExtSS.IsDone() && ( myExtSS.NbExt() > 0);

  if ( myIsDone) {

    // evaluate the lower distance and its index;
    
    Standard_Real Dist, DistMin = myExtSS.Value(1);
    myIndex = 1;
    
    for ( Standard_Integer i = 2; i <= myExtSS.NbExt(); i++) {
      Dist = myExtSS.Value(i);
      if ( Dist < DistMin) {
	DistMin = Dist;
	myIndex = i;
      }
    }
  }
}


//=======================================================================
//function : Init
//purpose  : 
//=======================================================================

void GeomAPI_ExtremaSurfaceSurface::Init
  (const Handle(Geom_Surface)& S1,
   const Handle(Geom_Surface)& S2, 
   const Standard_Real         U1min,
   const Standard_Real         U1max,
   const Standard_Real         V1min,
   const Standard_Real         V1max,
   const Standard_Real         U2min,
   const Standard_Real         U2max,
   const Standard_Real         V2min,
   const Standard_Real         V2max)
{
  GeomAdaptor_Surface TheSurface1 (S1,U1min,U1max,V1min,V1max);
  GeomAdaptor_Surface TheSurface2 (S2,U2min,U2max,V2min,V2max);

  Standard_Real Tol = Precision::PConfusion();
  Extrema_ExtSS theExtSS(TheSurface1, TheSurface2,
			  U1min,U1max,V1min,V1max,
			  U2min,U2max,V2min,V2max,
			  Tol,Tol);

  myExtSS = theExtSS;
  myIsDone = myExtSS.IsDone() && ( myExtSS.NbExt() > 0);

  if ( myIsDone) {

    // evaluate the lower distance and its index;
    
    Standard_Real Dist, DistMin = myExtSS.Value(1);
    myIndex = 1;
    
    for ( Standard_Integer i = 2; i <= myExtSS.NbExt(); i++) {
      Dist = myExtSS.Value(i);
      if ( Dist < DistMin) {
	DistMin = Dist;
	myIndex = i;
      }
    }
  }
}


//=======================================================================
//function : NbExtrema
//purpose  : 
//=======================================================================

Standard_Integer GeomAPI_ExtremaSurfaceSurface::NbExtrema() const 
{
  if ( myIsDone) 
    return myExtSS.NbExt();
  else
    return 0;
}


//=======================================================================
//function : Points
//purpose  : 
//=======================================================================

void GeomAPI_ExtremaSurfaceSurface::Points
  (const Standard_Integer Index,
         gp_Pnt&          P1,
         gp_Pnt&          P2) const 
{
  Standard_OutOfRange_Raise_if( Index < 1 || Index > NbExtrema(),
			       "GeomAPI_ExtremaCurveCurve::Points");

  Extrema_POnSurf PS1,PS2;
  myExtSS.Points(Index,PS1,PS2);

  P1 = PS1.Value();
  P2 = PS2.Value();
}


//=======================================================================
//function : Parameters
//purpose  : 
//=======================================================================

void GeomAPI_ExtremaSurfaceSurface::Parameters
  (const Standard_Integer Index,
         Standard_Real&   U1,
         Standard_Real&   V1,
         Standard_Real&   U2,
         Standard_Real&   V2) const 
{
  Standard_OutOfRange_Raise_if( Index < 1 || Index > NbExtrema(),
			       "GeomAPI_ExtremaCurveCurve::Parameters");

  Extrema_POnSurf PS1,PS2;
  myExtSS.Points(Index,PS1,PS2);

  PS1.Parameter(U1,V1);
  PS2.Parameter(U2,V2);
}


//=======================================================================
//function : Distance
//purpose  : 
//=======================================================================

Standard_Real GeomAPI_ExtremaSurfaceSurface::Distance
  (const Standard_Integer Index) const 
{
  Standard_OutOfRange_Raise_if( Index < 1 || Index > NbExtrema(),
			       "GeomAPI_ExtremaCurveCurve::Distance");

  return myExtSS.Value(Index);
}


//=======================================================================
//function : NearestPoints
//purpose  : 
//=======================================================================

void GeomAPI_ExtremaSurfaceSurface::NearestPoints
  (gp_Pnt& P1, 
   gp_Pnt& P2) const 
{
  StdFail_NotDone_Raise_if
    ( !myIsDone, "GeomAPI_ExtremaSurfaceSurface::NearestPoints");

  Points(myIndex,P1,P2);
}


//=======================================================================
//function : LowerDistanceParameters
//purpose  : 
//=======================================================================

void GeomAPI_ExtremaSurfaceSurface::LowerDistanceParameters
  (Standard_Real& U1,
   Standard_Real& V1,
   Standard_Real& U2,
   Standard_Real& V2) const 
{
  StdFail_NotDone_Raise_if
    ( !myIsDone, "GeomAPI_ExtremaSurfaceSurface::LowerDistanceParameters");

  Parameters(myIndex,U1,V1,U2,V2);
}


//=======================================================================
//function : LowerDistance
//purpose  : 
//=======================================================================

Standard_Real GeomAPI_ExtremaSurfaceSurface::LowerDistance() const 
{
  StdFail_NotDone_Raise_if
    ( !myIsDone, "GeomAPI_ExtremaSurfaceSurface::LowerDistance");

  return myExtSS.Value(myIndex);
}


//=======================================================================
//function : Standard_Real
//purpose  : 
//=======================================================================

GeomAPI_ExtremaSurfaceSurface::operator Standard_Real() const
{
  return LowerDistance();
}


//=======================================================================
//function : Standard_Integer
//purpose  : 
//=======================================================================

GeomAPI_ExtremaSurfaceSurface::operator Standard_Integer() const
{
  return NbExtrema();
}



