// Created on: 1993-03-22
// Created by: Laurent BUCHARD
// Copyright (c) 1993-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#include <TColStd_Array1OfReal.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec2d.hxx>
#include <gp_Vec.hxx>
#include <IntSurf_LineOn2S.hxx>
#include <Precision.hxx>
#include <math_Vector.hxx>

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

//=======================================================================
//function : Constructor
//purpose  : 
//=======================================================================
ApproxInt_MultiLine::ApproxInt_MultiLine()
{
  PtrOnmySvSurfaces = NULL;
  myLine = NULL;
  indicemin = 0;
  indicemax = 0;
  nbp3d = 0;
  nbp2d = 0;
  myApproxU1V1 = Standard_False;
  myApproxU2V2 = Standard_False;
  p2donfirst = Standard_True;
  Xo = 0.;
  Yo = 0.;
  Zo = 0.;
  U1o = 0.;
  V1o = 0.;
  U2o = 0.;
  V2o = 0.;
}

//=======================================================================
//function : Constructor
//purpose  : 
//=======================================================================
ApproxInt_MultiLine::
  ApproxInt_MultiLine(const Handle_TheLine& line,
                      const Standard_Address svsurf,
                      const Standard_Integer NbP3d,
                      const Standard_Integer NbP2d,
                      const Standard_Boolean ApproxU1V1,
                      const Standard_Boolean ApproxU2V2,
                      const Standard_Real xo,
                      const Standard_Real yo,
                      const Standard_Real zo,
                      const Standard_Real u1o,
                      const Standard_Real v1o,
                      const Standard_Real u2o,
                      const Standard_Real v2o,
                      const Standard_Boolean P2DOnFirst,
                      const Standard_Integer IndMin,
                      const Standard_Integer IndMax): PtrOnmySvSurfaces(svsurf),
                                                      myLine(line),
                                                      indicemin(Min(IndMin, IndMax)),
                                                      indicemax(Max(IndMin, IndMax)),
                                                      nbp3d(NbP3d), nbp2d(NbP2d),
                                                      myApproxU1V1(ApproxU1V1),
                                                      myApproxU2V2(ApproxU2V2),
                                                      p2donfirst(P2DOnFirst),
                                                      Xo(xo), Yo(yo), Zo(zo),
                                                      U1o(u1o), V1o(v1o),
                                                      U2o(u2o), V2o(v2o)

{
#ifdef OCCT_DEBUG
  //if(indicemin == indicemax)
  //{
  //  cout<<"ApproxInt_MultiLine: indicemin = indicemax = " << indicemin << endl;
  //}
#endif
}

//=======================================================================
//function : Constructor
//purpose  : 
//=======================================================================
ApproxInt_MultiLine::
  ApproxInt_MultiLine(const Handle_TheLine& line,
                      const Standard_Integer NbP3d,
                      const Standard_Integer NbP2d,
                      const Standard_Boolean ApproxU1V1,
                      const Standard_Boolean ApproxU2V2,
                      const Standard_Real xo,
                      const Standard_Real yo,
                      const Standard_Real zo,
                      const Standard_Real u1o,
                      const Standard_Real v1o,
                      const Standard_Real u2o,
                      const Standard_Real v2o,
                      const Standard_Boolean P2DOnFirst,
                      const Standard_Integer IndMin,
                      const Standard_Integer IndMax): PtrOnmySvSurfaces(0),
                                                      myLine(line),
                                                      indicemin(Min(IndMin, IndMax)),
                                                      indicemax(Max(IndMin, IndMax)),
                                                      nbp3d(NbP3d), nbp2d(NbP2d),
                                                      myApproxU1V1(ApproxU1V1),
                                                      myApproxU2V2(ApproxU2V2),
                                                      p2donfirst(P2DOnFirst),
                                                      Xo(xo), Yo(yo), Zo(zo),
                                                      U1o(u1o), V1o(v1o),
                                                      U2o(u2o), V2o(v2o)
{
#ifdef OCCT_DEBUG
  //if(indicemin == indicemax)
  //{
  //  cout<<"ApproxInt_MultiLine: indicemin = indicemax = " << indicemin << endl;
  //}
#endif
}

//--------------------------------------------------------------------------------
Standard_Integer ApproxInt_MultiLine::FirstPoint() const { 
  return indicemin;
}
//--------------------------------------------------------------------------------
Standard_Integer ApproxInt_MultiLine::LastPoint() const { 
  return indicemax;
}
//--------------------------------------------------------------------------------
Approx_Status ApproxInt_MultiLine::WhatStatus() const { 
  if(PtrOnmySvSurfaces)
    return Approx_PointsAdded;
  else 
    return Approx_NoPointsAdded;
}
//--------------------------------------------------------------------------------
Standard_Integer ApproxInt_MultiLine::NbP3d() const { 
  return nbp3d;
}
//--------------------------------------------------------------------------------
Standard_Integer ApproxInt_MultiLine::NbP2d() const { 
  return nbp2d;
}
//================================================================================
void ApproxInt_MultiLine::Value(const Standard_Integer  Index,
                                TColgp_Array1OfPnt&     TabPnt)  const
{
  const gp_Pnt aP = myLine->Point(Index).Value();
  TabPnt(1).SetCoord(aP.X()+Xo, aP.Y()+Yo, aP.Z()+Zo);
}

//=======================================================================
//function : Value
//purpose  : 
//=======================================================================
void ApproxInt_MultiLine::Value(const Standard_Integer Index,
                                TColgp_Array1OfPnt2d&  TabPnt2d) const 
{
  IntSurf_PntOn2S POn2S(myLine->Point(Index));
  Standard_Real u1 = 0.0, u2 = 0.0, v1 = 0.0, v2 = 0.0;
  POn2S.Parameters(u1, v1, u2, v2);
  if(nbp2d==1)
  { 
    if(p2donfirst)
    { 
      TabPnt2d(1).SetCoord(u1+U1o, v1+V1o);
    }
    else
    {
      TabPnt2d(1).SetCoord(u2+U2o, v2+V2o);
    }
  }
  else
  {
    TabPnt2d(1).SetCoord(u1+U1o, v1+V1o);
    if(TabPnt2d.Length() >= 2)
    { 
      TabPnt2d(2).SetCoord(u2+U2o, v2+V2o);
    } 
  }
}

//=======================================================================
//function : Value
//purpose  : 
//=======================================================================
void ApproxInt_MultiLine::Value(const Standard_Integer Index,
                                TColgp_Array1OfPnt&    TabPnt,
                                TColgp_Array1OfPnt2d&  TabPnt2d)  const 
{ 
    Value(Index, TabPnt);
    Value(Index, TabPnt2d);
}

//=======================================================================
//function : Tangency
//purpose  : 
//=======================================================================
Standard_Boolean ApproxInt_MultiLine::Tangency( const Standard_Integer Index,
                                                TColgp_Array1OfVec&    TabVec) const 
{
  if(PtrOnmySvSurfaces==NULL) 
    return Standard_False;

  const IntSurf_PntOn2S& POn2S = myLine->Point(Index);
  Standard_Real u1 = 0.0, u2 = 0.0, v1 = 0.0, v2 = 0.0;
  POn2S.Parameters(u1,v1,u2,v2);

  Standard_Boolean ret=
            ((TheSvSurfaces *)PtrOnmySvSurfaces)->Tangency(u1, v1, u2, v2, TabVec(1));
  if(!ret)
  {
    TabVec(1).SetCoord(0.0, 0.0, 0.0);
  }

  return ret;
}

//=======================================================================
//function : Tangency
//purpose  : 
//=======================================================================
Standard_Boolean ApproxInt_MultiLine::Tangency( const Standard_Integer Index,
                                                TColgp_Array1OfVec2d&  TabVec2d) const 
{
  if(PtrOnmySvSurfaces==NULL) 
    return Standard_False;

  const IntSurf_PntOn2S& POn2S = myLine->Point(Index);
  Standard_Real u1 = 0.0, u2 = 0.0, v1 = 0.0, v2 = 0.0;
  POn2S.Parameters(u1,v1,u2,v2);

  Standard_Boolean ret = Standard_False;
  if(nbp2d==1)
  { 
    if(p2donfirst)
    {
      ret=((TheSvSurfaces *)PtrOnmySvSurfaces)->TangencyOnSurf1(u1, v1, u2, v2, TabVec2d(1));
    }
    else
    { 
      ret=((TheSvSurfaces *)PtrOnmySvSurfaces)->TangencyOnSurf2(u1, v1, u2, v2, TabVec2d(1));
    }
  }
  else
  {
    ret=((TheSvSurfaces *)PtrOnmySvSurfaces)->TangencyOnSurf1(u1, v1, u2, v2, TabVec2d(1));
    if(ret)
    { 
      if(TabVec2d.Length()>=2)
      {
        ret = 
              (ret && 
              ((TheSvSurfaces *)PtrOnmySvSurfaces)->
                                          TangencyOnSurf2(u1, v1, u2, v2, TabVec2d(2)));
      }
    }
  }

  if(!ret)
  {
    TabVec2d(1) = gp_Vec2d(0.0, 0.0);
    if(TabVec2d.Length() >= 2)
    {
      TabVec2d(2) = gp_Vec2d(0.0,0.0);
    }
  }

  return ret;
}

//=======================================================================
//function : Tangency
//purpose  : 
//=======================================================================
Standard_Boolean ApproxInt_MultiLine::Tangency( const Standard_Integer Index,
                                                TColgp_Array1OfVec& TabVec,
                                                TColgp_Array1OfVec2d& TabVec2d) const
{ 
  return (Tangency(Index, TabVec) && Tangency(Index, TabVec2d));
}

//=======================================================================
//function : MakeMLBetween
//purpose  : 
//=======================================================================
ApproxInt_MultiLine
  ApproxInt_MultiLine::MakeMLBetween( const Standard_Integer Low,
                                      const Standard_Integer High,
                                      const Standard_Integer aNbPntsToInsert) const
{ 
  if(PtrOnmySvSurfaces==NULL) {
    //-- cout<<"\n Erreur dans : ApproxInt_MultiLine  ApproxInt_MultiLine::MakeMLBetween "<<endl;
    Handle(IntSurf_LineOn2S) vide1 = new IntSurf_LineOn2S();
    Handle(TheLine) vide = new TheLine(vide1,Standard_False);
    return (ApproxInt_MultiLine(vide,
                                NULL,
                                nbp3d,
                                nbp2d,
                                myApproxU1V1, myApproxU2V2,
                                Xo,Yo,Zo,U1o,V1o,U2o,V2o,
                                p2donfirst,
                                1,1));
    //-- return(*this);
  }

  Standard_Boolean aSaveUseSolver = ((TheSvSurfaces *)PtrOnmySvSurfaces)->GetUseSolver();
  if (!aSaveUseSolver)
  {
    ((TheSvSurfaces *)PtrOnmySvSurfaces)->SetUseSolver(Standard_True);
  }
  Standard_Integer NbPntsToInsert=aNbPntsToInsert;
  if(NbPntsToInsert<(High-Low)) NbPntsToInsert=(High-Low);
  Standard_Integer NbPnts = NbPntsToInsert + High - Low + 1;
  Standard_Integer NbPntsmin = High-Low;
  NbPntsmin+=NbPntsmin;
  
  if(NbPnts<NbPntsmin) NbPnts=NbPntsmin;


  gp_Vec T;
  gp_Vec2d TS1,TS2;
  gp_Pnt P;
  
  //-----------------------l-------------------------------------------
  //--  Indice     :   Low       Low+1     I    I+1         High    --
  //--                                                              --
  //--  Abs.Curv.  :  S(Low)              S(I)  S(I+1)      S(High) --
  //--                                                              --
  //--                On echantillonne a abcisse curviligne         --
  //--                constante.                                    --
  //--                L abcisse est calculee sur les params U1,V1   --
  //------------------------------------------------------------------
  TColStd_Array1OfReal U1(Low,High);
  TColStd_Array1OfReal V1(Low,High);
  TColStd_Array1OfReal U2(Low,High);
  TColStd_Array1OfReal V2(Low,High);
  TColStd_Array1OfReal AC(Low,High);
  Standard_Real s,ds;
  
  //------------------------------------------------------------
  //-- Creation des Tableaux U1 .. V2 et AC
  //-- 
  Standard_Real u1,v1,u2,v2;
  Standard_Integer i ;
  myLine->Point(Low).Parameters(u1,v1,u2,v2);
  U1(Low) = u1;
  V1(Low) = v1;
  U2(Low) = u2;
  V2(Low) = v2;
  AC(Low) =0.0;
  
#if 0 
  for( i=Low+1; i<=High; i++) { 
    myLine->Point(i).Parameters(u1,v1,u2,v2);
    U1(i) = u1;
    V1(i) = v1;
    U2(i) = u2;
    V2(i) = v2;
    
    Standard_Real du1=u1-U1(i-1);
    Standard_Real dv1=v1-V1(i-1);
    
    AC(i) = AC(i-1) + sqrt((du1*du1)+(dv1*dv1));
  }
#else 
  //-- Essai du 19 juin 96 (parametrage selon abs curv en XYZ)
  for( i=Low+1; i<=High; i++) { 
    myLine->Point(i).Parameters(u1,v1,u2,v2);
    U1(i) = u1;
    V1(i) = v1;
    U2(i) = u2;
    V2(i) = v2;    
    AC(i) = AC(i-1) + (myLine->Point(i-1).Value()).Distance(myLine->Point(i).Value());
  }

#endif
  //-------------------------------------------------------------
  //-- Creation des structures contenant les resultats
  
  Handle(IntSurf_LineOn2S) ResultPntOn2SLine = new IntSurf_LineOn2S();
  
  IntSurf_PntOn2S StartPOn2S;  
  TColStd_Array1OfReal StartParams(1,4);  
  
  ds = AC(High) / (NbPnts-1);
  Standard_Integer Indice = Low;
  Standard_Boolean HasBeenInserted = Standard_False;
  Standard_Real dsmin = ds*0.3;
  Standard_Real smax  = AC(High);
  
  for(i=2,s=ds; (s < smax && Indice <= High-1); i++,s+=ds) { 
    //----------------------------------------------------------
    //-- Recherche des indices des points                     --
    //-- Point           :    2       i       NbPnts-1        --
    //-- s                            s                       --
    //-- Current Indice tel que AC(Indice)<= s < AC(Indice+1) --
    //----------------------------------------------------------
    while(AC(Indice+1) <= s)
    { 
      if(!HasBeenInserted)
        ResultPntOn2SLine->Add(myLine->Point(Indice));

      HasBeenInserted = Standard_False;
      Indice++;
      if (Indice == High)
        break;
    }
    
    if (Indice == High)
      break;
    
    if(!HasBeenInserted  && AC(Indice) <= s)
    { 
      ResultPntOn2SLine->Add(myLine->Point(Indice));
      HasBeenInserted = Standard_True;
    }
    
    Standard_Real a = s - AC(Indice);
    Standard_Real b = AC(Indice+1) - s;
    Standard_Real nab = 1.0/(a+b);
    
    //----------------------------------------------------------
    //-- Verification :  Si Dist au prochain  point < dsmin   --
    //--                 Si Dist au precedent point < dsmin   --
    //--                                                      --
    //----------------------------------------------------------
    if((a>dsmin) && (b>dsmin))
    {
      u1 = (U1(Indice) * b   +  U1(Indice+1) * a) * nab;
      v1 = (V1(Indice) * b   +  V1(Indice+1) * a) * nab;
      u2 = (U2(Indice) * b   +  U2(Indice+1) * a) * nab;
      v2 = (V2(Indice) * b   +  V2(Indice+1) * a) * nab;
            
      if(((TheSvSurfaces *)PtrOnmySvSurfaces)->Compute(u1,v1,u2,v2,P,T,TS1,TS2))
      {
        StartPOn2S.SetValue(P,u1,v1,u2,v2);
        //-- cout<<" Insertion du point calcule : "<<u1<<","<<v1<<","<<u2<<","<<v2<<",";
        //-- cout<<P.X()<<","<<P.Y()<<","<<P.Z()<<endl;
        ResultPntOn2SLine->Add(StartPOn2S);
      }
      else
      {
        //-- cout<<" Probleme Non Traite ds ApproxInt_ApproxIntIntersection "<<endl;
      }
    }
    else
    {
      //-- Point non situe a distance suffisante de 2 pts existants
      //-- avec le point p[indice] deja insere
      
      if(b<0.0)
      {
        while(AC(Indice+1) <= s)
        {
          if(!HasBeenInserted)
            ResultPntOn2SLine->Add(myLine->Point(Indice));

          //-- cout<<" Insertion du point :"<<Indice<<endl;
          HasBeenInserted = Standard_False;
          Indice++;

          if (Indice == High)
            break;
        }

        if(Indice == High)
          break;

        if(!HasBeenInserted  && AC(Indice) <= s)
        {
          ResultPntOn2SLine->Add(myLine->Point(Indice));
          HasBeenInserted = Standard_True;
        }
      }
      else
      {
        s+= (dsmin - ds);
      }
    }
  }
  
  ResultPntOn2SLine->Add(myLine->Point(High));     //--  Point NbPnts
  Handle(TheLine) temp = new TheLine(ResultPntOn2SLine,Standard_False);
  
  //-- Verification   a posteriori 
  //-- On verifie qu il n y a pas de virage trop important en 2d et en 3d
  
  temp->Point(1).Parameters(u1,v1,u2,v2);
  gp_Pnt2d P1A(u1,v1);
  gp_Pnt2d P2A(u2,v2);

  temp->Point(2).Parameters(u1,v1,u2,v2);
  gp_Pnt2d P1B(u1,v1);
  gp_Pnt2d P2B(u2,v2);

  gp_Pnt2d P1C,P2C;

  Standard_Integer CodeErreur=0; 
  
  for(i=3,NbPnts=temp->NbPnts();CodeErreur==0 &&  i<=NbPnts; i++)
  {
    Standard_Real d,du,dv,duv2;
    temp->Point(i).Parameters(u1,v1,u2,v2);
    //-- Virage P1A P1B P1C
    P1C.SetCoord(u1,v1);
    du  = P1B.X()-P1A.X();
    dv  = P1B.Y()-P1A.Y();
    duv2= 0.25*(du*du+dv*dv);
    u1 = P1B.X() + du;
    v1 = P1B.Y() + dv;
    du = P1C.X() - u1;
    dv = P1C.Y() - v1;
    d = du*du+dv*dv;
    if(d>duv2)
    { 
      CodeErreur = 1;
      CodeErreur = 1;
      break;
    }
    
    //-- Virage P2A P2B P2C
    P2C.SetCoord(u2,v2);
    du  = P2B.X()-P2A.X();
    dv  = P2B.Y()-P2A.Y();
    duv2= 0.25*(du*du+dv*dv);
    u2 = P2B.X() + du;
    v2 = P2B.Y() + dv;
    du = P2C.X() - u2;
    dv = P2C.Y() - v2;
    d = du*du+dv*dv;
    if(d>duv2)
    {
      CodeErreur = 2;
      break;
    }
    
    P1A=P1B;
    P2A=P2B;
    P1B=P1C;
    P2B=P2C;
  }

#ifdef OCCT_DEBUG
  //if (temp->NbPnts() < NbPntsToInsert + High - Low + 1)
  //{ 
  //  cout<<" *** Pas assez de points entre :"<<
  //            Low<<" et "<<High<<" -> "<<temp->NbPnts()<<endl;
  //}

  //if(CodeErreur)
  //{ 
  //  cout<<" *** CodeErreur : "<<CodeErreur<<endl;
  //}
#endif

  if((temp->NbPnts() >= NbPntsToInsert + High - Low + 1) && (CodeErreur==0))
  {
    ((TheSvSurfaces *)PtrOnmySvSurfaces)->SetUseSolver(aSaveUseSolver);
    return (ApproxInt_MultiLine( temp, 
                                 (High-Low>10)? PtrOnmySvSurfaces : NULL,
                                 nbp3d,
                                 nbp2d,
                                 myApproxU1V1, myApproxU2V2,
                                 Xo,Yo,Zo,
                                 U1o,V1o,
                                 U2o,V2o,
                                 p2donfirst,
                                 1,ResultPntOn2SLine->NbPoints()));
  }
  else
  {
    //-- cout<<" ApproxInt_MultiLine "<<endl;
    //-- cout<<" Pas de Rajout de points ds1min =  "<<minds1<<" ds2min = "<<minds2<<endl;
    ((TheSvSurfaces *)PtrOnmySvSurfaces)->SetUseSolver(aSaveUseSolver);
    Handle(IntSurf_LineOn2S) vide1 = new IntSurf_LineOn2S();
    Handle(TheLine) vide = new TheLine(vide1,Standard_False);
    return (ApproxInt_MultiLine( vide,
                                 NULL,
                                 nbp3d,
                                 nbp2d,
                                 myApproxU1V1, myApproxU2V2,
                                 Xo,Yo,Zo,
                                 U1o,V1o,
                                U2o,V2o,
                                 p2donfirst,
                                 1,1));
  }
}

//=======================================================================
//function : MakeMLOneMorePoint
//purpose  : 
//=======================================================================
Standard_Boolean
  ApproxInt_MultiLine::MakeMLOneMorePoint(const Standard_Integer theLow,
                                          const Standard_Integer theHigh,
                                          const Standard_Integer theIndbad,
                                          ApproxInt_MultiLine& theNewMultiLine) const
{
  Standard_Boolean OtherLineMade = Standard_False;
  if(PtrOnmySvSurfaces==NULL)
    return Standard_False;

  Standard_Boolean aSaveUseSolver = ((TheSvSurfaces *)PtrOnmySvSurfaces)->GetUseSolver();
  if (!aSaveUseSolver)
  {
    ((TheSvSurfaces *)PtrOnmySvSurfaces)->SetUseSolver(Standard_True);
  }

  const Standard_Real SqTol3d = Precision::SquareConfusion();
  math_Vector tolerance(1,2);
  tolerance(1) = tolerance(2) = 1.e-8;
  
  Handle(IntSurf_LineOn2S) ResultPntOn2SLine = new IntSurf_LineOn2S();
  for (Standard_Integer Indice = theLow; Indice <= theHigh; Indice++)
    ResultPntOn2SLine->Add(myLine->Point(Indice));

  //Insert new point between (theIndbad-1) and theIndbad
  //Using <thePtrSVSurf> for Rsnld: it may be ImpPrm or PrmPrm
  gp_Pnt PrevPnt = myLine->Point(theIndbad-1).Value();
  gp_Pnt CurPnt  = myLine->Point(theIndbad).Value();
  Standard_Real uprev1, vprev1, uprev2, vprev2, ucur1, vcur1, ucur2, vcur2;
  myLine->Point(theIndbad-1).Parameters(uprev1, vprev1, uprev2, vprev2);
  myLine->Point(theIndbad).Parameters(ucur1, vcur1, ucur2, vcur2);
  Standard_Real umid1, vmid1, umid2, vmid2;
  umid1 = (uprev1 + ucur1)/2;
  vmid1 = (vprev1 + vcur1)/2;
  umid2 = (uprev2 + ucur2)/2;
  vmid2 = (vprev2 + vcur2)/2;
  IntSurf_PntOn2S MidPoint;
  Standard_Boolean IsNewPointInvalid = Standard_False;
  IsNewPointInvalid =
    myApproxU1V1 &&
    Abs(ucur1 - umid1) <= tolerance(1) &&
    Abs(vcur1 - vmid1) <= tolerance(2);
  if (!IsNewPointInvalid)
  {
    IsNewPointInvalid =
      myApproxU2V2 &&
      Abs(ucur2 - umid2) <= tolerance(1) &&
      Abs(vcur2 - vmid2) <= tolerance(2);
    if (!IsNewPointInvalid &&
        ((TheSvSurfaces *)PtrOnmySvSurfaces)->SeekPoint(umid1, vmid1, umid2, vmid2,
                                                        MidPoint))
    {
      const gp_Pnt& NewPnt = MidPoint.Value();
      Standard_Real SqDistNewPrev = NewPnt.SquareDistance(PrevPnt);
      Standard_Real SqDistNewCur  = NewPnt.SquareDistance(CurPnt);
      IsNewPointInvalid = (SqDistNewPrev <= SqTol3d ||
                           SqDistNewCur  <= SqTol3d);
      if (!IsNewPointInvalid)
      {
        Standard_Real unew1, vnew1, unew2, vnew2;
        MidPoint.Parameters(unew1, vnew1, unew2, vnew2);
        if (myApproxU1V1)
        {
          Standard_Real SqDistCurMid1 =
            (ucur1 - umid1)*(ucur1 - umid1)+(vcur1 - vmid1)*(vcur1 - vmid1);
          Standard_Real SqDistMidNew1 =
            (umid1 - unew1)*(umid1 - unew1)+(vmid1 - vnew1)*(vmid1 - vnew1);
          IsNewPointInvalid = (SqDistMidNew1 > SqDistCurMid1);
        }
        if (!IsNewPointInvalid)
        {
          if (myApproxU2V2)
          {
            Standard_Real SqDistCurMid2 =
              (ucur2 - umid2)*(ucur2 - umid2)+(vcur2 - vmid2)*(vcur2 - vmid2);
            Standard_Real SqDistMidNew2 =
              (umid2 - unew2)*(umid2 - unew2)+(vmid2 - vnew2)*(vmid2 - vnew2);
            IsNewPointInvalid = (SqDistMidNew2 > SqDistCurMid2);
          }
          if (!IsNewPointInvalid)
          {
            ResultPntOn2SLine->InsertBefore(theIndbad-theLow+1, MidPoint);
            OtherLineMade = Standard_True;
          }
        }
      }
    }
  }

  if (!OtherLineMade)
  {
    ((TheSvSurfaces *)PtrOnmySvSurfaces)->SetUseSolver(aSaveUseSolver);
    return Standard_False;
  }

#ifdef DRAW
  char* name = new char[100];
  Standard_Integer indc = 1;
  Standard_Boolean onfirst = Standard_True;
  for (Standard_Integer i = 1; i <= ResultPntOn2SLine->NbPoints(); i++)
  {
    const IntSurf_PntOn2S& thePoint = ResultPntOn2SLine->Value(i);
    gp_Pnt curPnt = thePoint.Value();
    sprintf(name, "p%d_%d", indc, i);
    DrawTrSurf::Set(name, curPnt);
    gp_Pnt2d curPnt2d = thePoint.ValueOnSurface(onfirst);
    sprintf(name, "pp%d_%d", indc, i);
    DrawTrSurf::Set(name, curPnt2d);
  }
#endif
  Handle(TheLine) temp = new TheLine(ResultPntOn2SLine,Standard_False);
  ((TheSvSurfaces *)PtrOnmySvSurfaces)->SetUseSolver(aSaveUseSolver);
  theNewMultiLine = ApproxInt_MultiLine( temp, 
                                         PtrOnmySvSurfaces,
                                         nbp3d,
                                         nbp2d,
                                         myApproxU1V1,
                                         myApproxU2V2,
                                         Xo,Yo,Zo,
                                         U1o,V1o,
                                         U2o,V2o,
                                         p2donfirst,
                                         1,ResultPntOn2SLine->NbPoints());
  return Standard_True;
}

//=======================================================================
//function : Dump
//purpose  : 
//=======================================================================
void ApproxInt_MultiLine::Dump() const
{
  TColgp_Array1OfPnt anArr1(1, 1);
  TColgp_Array1OfPnt2d anArr2(1, 2);
        
  const Standard_Integer  anIndF = FirstPoint(),
                          anIndL = LastPoint();
        
  for(Standard_Integer ind = anIndF; ind <= anIndL; ind++)
  {
    Value(ind, anArr1, anArr2);
    printf("%4d  [%+10.20f %+10.20f %+10.20f]  "
            "[%+10.20f %+10.20f]  [%+10.20f %+10.20f]\n",
      ind, anArr1(1).X(), anArr1(1).Y(), anArr1(1).Z(), anArr2(1).X(),
      anArr2(1).Y(),anArr2(2).X(),anArr2(2).Y());
  }
}

