// Created on: 1994-03-29
// Created by: Isabelle GRIGNON
// Copyright (c) 1994-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 <Adaptor3d_CurveOnSurface.hxx>
#include <Adaptor3d_CurveOnSurface.hxx>
#include <BRep_Tool.hxx>
#include <BRepBlend_Line.hxx>
#include <BRepLProp_CLProps.hxx>
#include <BRepTopAdaptor_TopolTool.hxx>
#include <BSplCLib.hxx>
#include <ChFi3d.hxx>
#include <ChFi3d_Builder_0.hxx>
#include <ChFi3d_FilBuilder.hxx>
#include <ChFiDS_CommonPoint.hxx>
#include <ChFiDS_FaceInterference.hxx>
#include <ChFiDS_FilSpine.hxx>
#include <ChFiDS_HData.hxx>
#include <ChFiDS_Regul.hxx>
#include <ChFiDS_SequenceOfSurfData.hxx>
#include <ChFiDS_Spine.hxx>
#include <ChFiDS_State.hxx>
#include <ChFiDS_Stripe.hxx>
#include <ChFiDS_SurfData.hxx>
#include <ChFiKPart_ComputeData.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom2d_TrimmedCurve.hxx>
#include <Geom2dAdaptor_Curve.hxx>
#include <Geom2dConvert.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomFill_ConstrainedFilling.hxx>
#include <GeomFill_SimpleBound.hxx>
#include <gp_Ax3.hxx>
#include <gp_Dir.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pnt2d.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_NotImplemented.hxx>
#include <StdFail_NotDone.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_ListOfInteger.hxx>
#include <TopAbs.hxx>
#include <TopAbs_Orientation.hxx>
#include <TopExp.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopOpeBRepDS_DataStructure.hxx>
#include <TopOpeBRepDS_HDataStructure.hxx>

#ifdef DRAW
#include <DrawTrSurf.hxx>
#endif
#ifdef OCCT_DEBUG
#include <Geom_TrimmedCurve.hxx>
extern Standard_Boolean ChFi3d_GettraceDRAWSPINE();
extern Standard_Boolean ChFi3d_GetcontextFORCEFILLING();
#include <OSD_Chronometer.hxx>

extern Standard_Real  t_t2cornerinit ,t_perf2cornerbyinter,t_chfikpartcompdata,
                     t_cheminement,t_remplissage,t_t2cornerDS;
extern void ChFi3d_InitChron(OSD_Chronometer& ch);
extern void ChFi3d_ResultChron(OSD_Chronometer & ch,Standard_Real& time);
#endif

//=======================================================================
//function : ToricRotule
//purpose  : Test if it is a particular case of torus routine.
//           Three planes with two constant incident fillets
//           of the same radius and the third face perpendicular to  
//           two others are required.
//=======================================================================

static Standard_Boolean ToricRotule(const BRepAdaptor_Surface& fac,
				    const BRepAdaptor_Surface& s1,
				    const BRepAdaptor_Surface& s2,
				    const Handle(ChFiDS_Stripe)& c1,
				    const Handle(ChFiDS_Stripe)& c2)

{
  Standard_Real tolesp = 1.e-7;

  Handle(ChFiDS_FilSpine) sp1=Handle(ChFiDS_FilSpine)::DownCast(c1->Spine()); 
  Handle(ChFiDS_FilSpine) sp2=Handle(ChFiDS_FilSpine)::DownCast(c2->Spine()); 
  if(sp1.IsNull() || sp2.IsNull()) return Standard_False;
  if (!sp1->IsConstant() || !sp2->IsConstant()) 
    return Standard_False;
  if ((fac.GetType() != GeomAbs_Plane) ||
      (s1.GetType() != GeomAbs_Plane) ||
      (s2.GetType() != GeomAbs_Plane)) return Standard_False;
  gp_Dir df = fac.Plane().Position().Direction();
  gp_Dir ds1 = s1.Plane().Position().Direction();
  gp_Dir ds2 = s2.Plane().Position().Direction();
  if ( Abs(df.Dot(ds1)) >= tolesp || Abs(df.Dot(ds2)) >= tolesp ) 
    return Standard_False;
  Standard_Real r1 = sp1->Radius();
  Standard_Real r2 = sp2->Radius();
  if(Abs(r1 - r2) >= tolesp) return Standard_False;
  return Standard_True;
}

static void RemoveSD(Handle(ChFiDS_Stripe)& Stripe,
		      const Standard_Integer num1,
                      const Standard_Integer num2 )
{
  ChFiDS_SequenceOfSurfData& Seq = 
    Stripe->ChangeSetOfSurfData()->ChangeSequence();
  if(Seq.IsEmpty()) return;
  if (num1==num2) 
    Seq.Remove(num1);
  else
    Seq.Remove(num1,num2);
}


//=======================================================================
//function : PerformTwoCorner
//purpose  : 
//=======================================================================

void ChFi3d_FilBuilder::PerformTwoCorner(const Standard_Integer Index)
{
#ifdef OCCT_DEBUG
  OSD_Chronometer ch;
  ChFi3d_InitChron(ch); // init perf initialisation 
#endif 
  
  done = 0;
  const TopoDS_Vertex& Vtx = myVDataMap.FindKey(Index);
  TopOpeBRepDS_DataStructure& DStr = myDS->ChangeDS();
  ChFiDS_ListIteratorOfListOfStripe It;
  It.Initialize(myVDataMap(Index));
  Handle(ChFiDS_Stripe)  st1,st2;
  Standard_Integer Sens1,Sens2;
  Standard_Integer Isd1,Isd2,i1,i2;
  Handle(ChFiDS_SurfData) sd1,sd2;
  ChFiDS_SequenceOfSurfData SeqFil1,SeqFil2;
  Handle(Geom_Surface) surf1,surf2;
  Standard_Boolean  OkinterCC,Okvisavis,SameSide;
  Standard_Integer IFaCo1,IFaCo2;
  Standard_Real UIntPC1,UIntPC2;
  TopoDS_Face FaCo;
  TopoDS_Edge E1,E2,E;
  TopoDS_Vertex V1,V2;
//  gp_Pnt P1,P2;
  Standard_Integer nbsurf1,nbsurf2,deb1,fin1,deb2,fin2;
  Standard_Real parE1,parE2;
  //Necessary information on fillets is extracted 
  //------------------------------------------------------
  
  //the first
  //----------
 
  st1 = It.Value(); 
  Isd1 = ChFi3d_IndexOfSurfData(Vtx,st1,Sens1);
  
  
  //the second
  //----------
  It.Next();
  st2 = It.Value();
  if(st2 == st1) {
    Sens2 = -1;
    Isd2 = st2->SetOfSurfData()->Length();
  }
  else{ Isd2 = ChFi3d_IndexOfSurfData(Vtx,st2,Sens2); }
  
  // If two edges to rounded are tangent GeomPlate is called

  if (Sens1==1)  E1= st1->Spine()->Edges(1);
  else E1= st1->Spine()->Edges( st1->Spine()->NbEdges());
  
  if (Sens2==1)  E2= st2->Spine()->Edges(1);
  else E2= st2->Spine()->Edges( st2->Spine()->NbEdges());
  
  BRepAdaptor_Curve BCurv1(E1);
  BRepAdaptor_Curve BCurv2(E2);
  parE1=BRep_Tool::Parameter(Vtx,E1);
  parE2=BRep_Tool::Parameter(Vtx,E2);
  BRepLProp_CLProps CL1(BCurv1,parE1 , 1, 1.e-4);
  BRepLProp_CLProps CL2(BCurv2,parE2 , 1, 1.e-4);
  gp_Dir dir1,dir2 ;
  CL1.Tangent(dir1);
  CL2.Tangent(dir2);
  if (Sens1==-1)  dir1.Reverse();
  if (Sens2==-1)  dir2.Reverse();
  Standard_Real ang1;
  ang1=Abs(dir1.Angle(dir2));
  if (ang1<M_PI/180.) {
    PerformMoreThreeCorner(Index,2);
    done=1;
    return;
  }

  OkinterCC = ChFi3d_IsInFront(DStr,st1,st2,Isd1,Isd2,Sens1,Sens2,
			       UIntPC1,UIntPC2,FaCo,SameSide,
			       IFaCo1,IFaCo2,Okvisavis,Vtx,Standard_True);

  Standard_Boolean trouve=Standard_False;  
  if (!Okvisavis) {

  
// one is not limited to the first or the last surfdata 
// to find the opposing data
    nbsurf1=st1->SetOfSurfData()->Length();
    nbsurf2=st2->SetOfSurfData()->Length();
    deb1=1; 
    deb2=1;
    fin1=1;
    fin2=1;
    if (nbsurf1!=1) {
      if (Sens1==1) {
	deb1=1;
	fin1=2;
      }
      else  {
	deb1=nbsurf1-1;
	fin1=nbsurf1;
      }
    }
    if (nbsurf2!=1) {
      if (Sens2==1 ) {
	deb2=1;
	fin2=2;
      }
      else {
	deb2=nbsurf2-1;
	fin2=nbsurf2;
      }
    }
  
    for (i1=deb1;i1<=fin1 &&!trouve;i1++) {
      Isd1=i1;
      for (i2=deb2;i2<=fin2 &&!trouve;i2++) {
	Isd2=i2;
 
        OkinterCC = ChFi3d_IsInFront(DStr,st1,st2,Isd1,Isd2,Sens1,Sens2,
			       UIntPC1,UIntPC2,FaCo,SameSide,
			       IFaCo1,IFaCo2,Okvisavis,Vtx,Standard_True);
        trouve=Okvisavis;
      }
    } 
    if (!trouve){
      PerformMoreThreeCorner(Index,2);
      done=1;
      return;
    }
    else {
      if (Sens1==1 && Isd1!=1) RemoveSD(st1,1,1);
      if (Sens1!=1 && Isd1!=nbsurf1) RemoveSD(st1,fin1,fin1);
      if (Sens2==1 && Isd2!=1) RemoveSD(st2,1,1);
      if (Sens2!=1 && Isd2!=nbsurf2) RemoveSD(st2,fin2,fin2);

    }
    Isd1=ChFi3d_IndexOfSurfData(Vtx,st1,Sens1);
    Isd2=ChFi3d_IndexOfSurfData(Vtx,st2,Sens2);
  }
   // throw StdFail_NotDone("TwoCorner : no common face");
  Standard_Integer IFaArc1 = 3-IFaCo1, IFaArc2 = 3-IFaCo2;
  SeqFil1 = st1->ChangeSetOfSurfData()->ChangeSequence();
  SeqFil2 = st2->ChangeSetOfSurfData()->ChangeSequence();
  sd1 = SeqFil1.ChangeValue(Isd1);
  surf1 = DStr.Surface(sd1->Surf()).Surface();
  sd2 = SeqFil2.ChangeValue(Isd2);
  surf2 = DStr.Surface(sd2->Surf()).Surface();
  TopAbs_Orientation OFaCo = FaCo.Orientation(); 
  // The concavities are analyzed and the opposite face and the
  // eventual intersection of 2 pcurves on this face are found.
  
  ChFiDS_State Stat1,Stat2;
  Standard_Boolean isfirst1 = (Sens1 == 1);
  Standard_Boolean isfirst2 = (Sens2 == 1);
  Stat1 = st1->Spine()->Status(isfirst1);
  Stat2 = st2->Spine()->Status(isfirst2);
  Standard_Boolean c1biseau = (Stat1 == ChFiDS_AllSame); 
  Standard_Boolean c1rotule = (Stat1 == ChFiDS_OnSame && Stat2 == ChFiDS_OnSame);
  
  // It is checked if the fillets have a commonpoint on a common arc. 
  // This edge is the pivot of the bevel or the knee.
  
  ChFiDS_CommonPoint& CP1 = sd1->ChangeVertex(isfirst1,IFaArc1);
  ChFiDS_CommonPoint& CP2 = sd2->ChangeVertex(isfirst2,IFaArc2);
  
  Standard_Boolean resetcp1 = 0;
  Standard_Boolean resetcp2 = 0;
  
  TopoDS_Edge pivot;
  Standard_Boolean yapiv = Standard_False;
  if(CP1.IsOnArc()) pivot = CP1.Arc();
  else {
    PerformMoreThreeCorner(Index,2);
    done=1;
    return;
  }
  if(CP1.IsOnArc()&& CP2.IsOnArc()){
    yapiv = (pivot.IsSame(CP2.Arc()));
  }
  Handle(BRepAdaptor_Curve) Hpivot;
  Standard_Boolean sameparam = Standard_False;
  Standard_Real parCP1 = 0., parCP2 = 0.;
  if(yapiv) {
    Hpivot = new BRepAdaptor_Curve(pivot);
    parCP1 = CP1.ParameterOnArc();
    parCP2 = CP2.ParameterOnArc();
    gp_Pnt tst1 = Hpivot->Value(parCP1);
    gp_Pnt tst2 = Hpivot->Value(parCP2);
    sameparam = tst1.Distance(tst2) <= tolapp3d;
  }
  Handle(BRepAdaptor_Surface) HFaCo = new BRepAdaptor_Surface();
  Handle(BRepAdaptor_Surface) HFaPiv;
  Handle(BRepAdaptor_Surface) HBRS1 = new BRepAdaptor_Surface();
  Handle(BRepAdaptor_Surface) HBRS2 = new BRepAdaptor_Surface();
  
  BRepAdaptor_Surface& BRS1 = *HBRS1;
  BRepAdaptor_Surface& BRS2 = *HBRS2;
  BRepAdaptor_Surface& BRFaCo = *HFaCo;
  BRFaCo.Initialize(FaCo);
  
  TopoDS_Face FF1,FF2,F,FaPiv;
  TopAbs_Orientation pctrans = TopAbs_FORWARD ;
  Handle(Geom2d_BSplineCurve) PCurveOnPiv;
  FF1 = TopoDS::Face(DStr.Shape(sd1->Index(IFaArc1)));
  FF2 = TopoDS::Face(DStr.Shape(sd2->Index(IFaArc2)));
  if (FF1.IsNull()||FF2.IsNull()) 
  {PerformMoreThreeCorner(Index,2);
   done=1;
   return;
  }
  BRS1.Initialize(FF1);
  BRS2.Initialize(FF2);
  
  if(yapiv ) {
    TopTools_ListIteratorOfListOfShape Kt;
    Standard_Boolean ok1 = Standard_False, ok2 = Standard_False;
    for (Kt.Initialize(myEFMap(pivot)); Kt.More(); Kt.Next()){
      F = TopoDS::Face(Kt.Value());
      if(!ok1 && FF1.IsSame(F)){
	ok1 = Standard_True;
      }
      if(!ok2 && FF2.IsSame(F)){
	ok2 = Standard_True;
      }
    }
    if(!ok1 || !ok2){
      PerformMoreThreeCorner(Index,2);
      done=1;
      return;
    }
  }
  
#ifdef OCCT_DEBUG
  ChFi3d_ResultChron(ch ,t_t2cornerinit);//result perf initialisation 
#endif 
  
  //bevel
  //------
  ChFiDS_CommonPoint cp11,cp12,cp21,cp22;
  ChFiDS_FaceInterference intf11,intf12,intf21,intf22;

  if(c1biseau){
#ifdef OCCT_DEBUG
    ChFi3d_InitChron(ch); // init perf PerformTwoCornerbyInter
#endif 
    
    done = PerformTwoCornerbyInter(Index);
    
#ifdef OCCT_DEBUG
    ChFi3d_ResultChron(ch , t_perf2cornerbyinter); // result perf  PerformTwoCornerbyInter
#endif 
   
    if (!done){
      PerformMoreThreeCorner(Index,2);
      done=1;
      return;
    }
  } 
  else if(c1rotule){//save.
    cp11 = sd1->Vertex(isfirst1,1);
    cp12 = sd1->Vertex(isfirst1,2);
    cp21 = sd2->Vertex(isfirst2,1);
    cp22 = sd2->Vertex(isfirst2,2);
    intf11 = sd1->InterferenceOnS1();
    intf12 = sd1->InterferenceOnS2();
    intf21 = sd2->InterferenceOnS1();
    intf22 = sd2->InterferenceOnS2();
#ifdef OCCT_DEBUG
    ChFi3d_InitChron(ch); // init perf PerformTwoCornerbyInter
#endif 
      
    done = PerformTwoCornerbyInter(Index);
      
#ifdef OCCT_DEBUG
      ChFi3d_ResultChron(ch , t_perf2cornerbyinter); // result perf  PerformTwoCornerbyInter
#endif 
    if (!done) {
      // restore
      sd1->ChangeVertex(isfirst1,1) = cp11;
      sd1->ChangeVertex(isfirst1,2) = cp12;
      sd2->ChangeVertex(isfirst2,1) = cp21;
      sd2->ChangeVertex(isfirst2,2) = cp22;
      sd1->ChangeInterferenceOnS1() = intf11;
      sd1->ChangeInterferenceOnS2() = intf12;
      sd2->ChangeInterferenceOnS1() = intf21;
      sd2->ChangeInterferenceOnS2() = intf22;
      done = 0;
    }
  }
  
  if(!c1biseau && !done){
    //new cornerdata is created
    //-------------------------------
    Handle(ChFiDS_Stripe) corner = new ChFiDS_Stripe();
    Handle(ChFiDS_HData)& cornerset = corner->ChangeSetOfSurfData();
    cornerset = new ChFiDS_HData();
    Handle(ChFiDS_SurfData) coin = new ChFiDS_SurfData();
    cornerset->Append(coin);
    
    if (SameSide) {
      if(ToricRotule(BRFaCo,BRS1,BRS2,st1,st2)){
	// Direct construction.
	// ---------------------
	
	Standard_Integer bid;
	TopAbs_Orientation ori = OFaCo;
	TopAbs_Orientation oriS = st1->Orientation(IFaCo1);
	TopAbs_Orientation OFF1 = FF1.Orientation(); 
	TopAbs_Orientation oriSFF1 = st1->Orientation(IFaArc1);
	bid = 1;
	bid = ChFi3d::NextSide(ori,OFF1,oriS,oriSFF1,bid);
	TopAbs_Orientation op1 = TopAbs_FORWARD,op2 = TopAbs_FORWARD;
	if(yapiv) bid = ChFi3d::ConcaveSide(BRS1,BRS2,pivot,op1,op2);
	op1 = TopAbs::Reverse(op1);
	op2 = TopAbs::Reverse(op2);
#ifdef OCCT_DEBUG
	ChFi3d_InitChron(ch);// init perf ChFiKPart_ComputeData 
#endif 
	Standard_Real radius = 
	  Handle(ChFiDS_FilSpine)::DownCast(st1->Spine())->Radius();
	done = ChFiKPart_ComputeData::ComputeCorner(DStr,coin,HFaCo,HBRS1,HBRS2,
						    OFaCo,ori,op1,op2,radius);
#ifdef OCCT_DEBUG
	ChFi3d_ResultChron(ch , t_chfikpartcompdata);//result perf ChFiKPart_ComputeData 
#endif 
      }
      else {
	// Construction by filling remplissage
	// ----------------------------
	Standard_Real  uPCArc1,  uPCArc2;
	gp_Pnt2d p2da1,p2df1,p2da2,p2df2,p2dfac1,p2dfac2;
	gp_Vec2d v2dfac1,v2dfac2;
	Handle(GeomFill_Boundary) B1,B2,Bpiv,Bfac;
	uPCArc1 = sd1->Interference(IFaArc1).Parameter(isfirst1);
	p2da1 = sd1->Interference(IFaArc1).PCurveOnSurf()->Value(uPCArc1);
	p2df1 = sd1->Interference(IFaCo1).PCurveOnSurf()->Value(uPCArc1);
	sd1->Interference(IFaCo1).PCurveOnFace()->D1(uPCArc1,p2dfac1,v2dfac1);
	uPCArc2 = sd2->Interference(IFaArc2).Parameter(isfirst2);
	p2da2 = sd2->Interference(IFaArc2).PCurveOnSurf()->Value(uPCArc2);
	p2df2 = sd2->Interference(IFaCo2).PCurveOnSurf()->Value(uPCArc2);
	sd2->Interference(IFaCo2).PCurveOnFace()->D1(uPCArc2,p2dfac2,v2dfac2);
#ifdef OCCT_DEBUG
	ChFi3d_InitChron(ch ); // init perf filling
#endif 
	B1 = ChFi3d_mkbound(surf1,p2df1,p2da1,tolapp3d,2.e-4);
	B2 = ChFi3d_mkbound(surf2,p2df2,p2da2,tolapp3d,2.e-4);
	Handle(Geom2d_Curve) PCurveOnFace;
	Bfac = ChFi3d_mkbound(HFaCo,PCurveOnFace,Sens1,p2dfac1,v2dfac1,
			      Sens2,p2dfac2,v2dfac2,tolapp3d,2.e-4);
	GeomFill_ConstrainedFilling fil(8,20);
	if(sameparam) {
	  fil.Init(Bfac,B2,B1,1);
	}
	else {
	  Handle(Adaptor3d_Curve) HPivTrim = Hpivot->Trim(Min(parCP1,parCP2),Max(parCP1,parCP2),tolesp);
	  Bpiv = new GeomFill_SimpleBound(HPivTrim,tolapp3d,2.e-4);
	  fil.Init(Bfac,B2,Bpiv,B1,1);
	  BRepAdaptor_Curve2d pcpivot;
	  gp_Vec dArc,dcf;
	  gp_Pnt bidon;
	  Hpivot->D1(parCP1,bidon,dArc);
	  Standard_Real fb1,lb1;
	  B1->Bounds(fb1,lb1);
	  B1->D1(lb1,bidon,dcf);
	  Standard_Boolean pivotverslebas = dArc.Dot(dcf) <= 0.; 
	  Standard_Boolean pcfalenvers = (parCP1 > parCP2);
	  if((pivotverslebas && !pcfalenvers)||
	     (!pivotverslebas && pcfalenvers)) {
	    FaPiv = FF2;
	    HFaPiv = HBRS2;
	    resetcp2 = 1;
	  }
	  else {
	    FaPiv = FF1;
	    HFaPiv = HBRS1;
	    resetcp1 = 1;
	  }
	  FaPiv.Orientation(TopAbs_FORWARD);
	  pcpivot.Initialize(pivot,FaPiv);
	  TopExp_Explorer Expl;
	  for(Expl.Init(FaPiv,TopAbs_EDGE); Expl.More(); Expl.Next()){
	    if(Expl.Current().IsSame(pivot)) {
	      pctrans = Expl.Current().Orientation();
	      break;
	    }
	  }
	  if(pcpivot.GetType() != GeomAbs_BSplineCurve){
	    Handle(Geom2d_TrimmedCurve) 
	      trc = new Geom2d_TrimmedCurve(pcpivot.Curve(),
					    Min(parCP1,parCP2),
					    Max(parCP1,parCP2));
	    PCurveOnPiv = Geom2dConvert::CurveToBSplineCurve(trc);
	  }
	  else {
	    PCurveOnPiv = Geom2dConvert::SplitBSplineCurve
	      (Handle(Geom2d_BSplineCurve)::DownCast(pcpivot.Curve()),
	       Min(parCP1,parCP2),Max(parCP1,parCP2),tol2d);
	  }
	  TColStd_Array1OfReal kk(1,PCurveOnPiv->NbKnots());
	  PCurveOnPiv->Knots(kk);
	  BSplCLib::Reparametrize(0.,1.,kk);
	  PCurveOnPiv->SetKnots(kk);
	  if(pcfalenvers) {
	    PCurveOnPiv->Reverse();
	    pctrans = TopAbs::Reverse(pctrans);
	  }
	}
	Handle(Geom_Surface) Surfcoin = fil.Surface();
	done = CompleteData(coin,Surfcoin,
			    HFaCo,PCurveOnFace,
			    HFaPiv,PCurveOnPiv,OFaCo,1,
			    0,0,0,0);
#ifdef OCCT_DEBUG
	ChFi3d_ResultChron(ch , t_remplissage);// result perf filling 
#endif 
      }
#ifdef OCCT_DEBUG
      ChFi3d_InitChron(ch); // init perf update DS
#endif 
      if (done){
	// Update 3 CornerData and the DS
	// ----------------------------------------
	if(resetcp1){
	  gp_Pnt pjyl = CP1.Point();
	  Standard_Real tolsav = CP1.Tolerance();
	  CP1.Reset();
	  CP1.SetPoint(pjyl);
	  CP1.SetTolerance(tolsav);
	}
	else if(resetcp2){
	  gp_Pnt pjyl = CP2.Point();
	  Standard_Real tolsav = CP2.Tolerance();
	  CP2.Reset();
	  CP2.SetPoint(pjyl);
	  CP2.SetTolerance(tolsav);
	}
	Standard_Real P1deb,P2deb,P1fin,P2fin;
	Standard_Integer If1,If2,Il1,Il2,Icf,Icl;
	const ChFiDS_CommonPoint& Pf1 = coin->VertexFirstOnS1();
	ChFiDS_CommonPoint& Pf2 = coin->ChangeVertexFirstOnS2();
	const ChFiDS_CommonPoint& Pl1 = coin->VertexLastOnS1();
	ChFiDS_CommonPoint& Pl2 = coin->ChangeVertexLastOnS2();
	Pf2 = CP1;
	Pl2 = CP2;
	
	// the corner to start,
	// -----------------------
	ChFiDS_Regul regdeb, regfin;
	If1 = ChFi3d_IndexPointInDS(Pf1,DStr);
	If2 = ChFi3d_IndexPointInDS(Pf2,DStr);
	Il1 = ChFi3d_IndexPointInDS(Pl1,DStr);
	if(sameparam) Il2 = If2;
	else Il2 = ChFi3d_IndexPointInDS(Pl2,DStr);
	
	gp_Pnt2d pp1,pp2;
	pp1 = coin->InterferenceOnS1().PCurveOnSurf()->
	  Value(coin->InterferenceOnS1().FirstParameter());
	pp2 = coin->InterferenceOnS2().PCurveOnSurf()->
	  Value(coin->InterferenceOnS2().FirstParameter());
	Handle(Geom_Curve) C3d;
	Standard_Real tolreached;
	ChFi3d_ComputeArete(Pf1,pp1,Pf2,pp2,
			    DStr.Surface(coin->Surf()).Surface(),C3d,
			    corner->ChangeFirstPCurve(),P1deb,P2deb,
			    tolapp3d,tol2d,tolreached,0);
	Standard_Real par1 = sd1->Interference(IFaArc1).Parameter(isfirst1);
	pp1 = sd1->Interference(IFaCo1).PCurveOnSurf()->Value(par1);
	pp2 = sd1->Interference(IFaArc1).PCurveOnSurf()->Value(par1);
	Standard_Real tolr1;
	ChFi3d_ComputePCurv(C3d,pp1,pp2,st1->ChangePCurve(isfirst1),
			    DStr.Surface(sd1->Surf()).Surface(),
			    P1deb,P2deb,tolapp3d,tolr1);
	tolreached = Max(tolreached,tolr1);
	TopOpeBRepDS_Curve Tcurv1(C3d,tolreached);
	Icf = DStr.AddCurve(Tcurv1);
	regdeb.SetCurve(Icf);
	regdeb.SetS1(coin->Surf(),0);
	regdeb.SetS2(sd1->Surf(),0);
	myRegul.Append(regdeb);
	corner->ChangeFirstCurve(Icf);
	corner->ChangeFirstParameters(P1deb,P2deb);
	corner->ChangeIndexFirstPointOnS1(If1);
	corner->ChangeIndexFirstPointOnS2(If2);
      
	pp1 = coin->InterferenceOnS1().PCurveOnSurf()->
	  Value(coin->InterferenceOnS1().LastParameter());
	pp2 = coin->InterferenceOnS2().PCurveOnSurf()->
	  Value(coin->InterferenceOnS2().LastParameter());
	ChFi3d_ComputeArete(Pl1,pp1,Pl2,pp2,
			    DStr.Surface(coin->Surf()).Surface(),C3d,
			    corner->ChangeLastPCurve(),P1fin,P2fin,
			    tolapp3d,tol2d,tolreached,0);
	Standard_Real par2 = sd2->Interference(IFaArc2).Parameter(isfirst2);
	pp1 = sd2->Interference(IFaCo2).PCurveOnSurf()->Value(par2);
	pp2 = sd2->Interference(IFaArc2).PCurveOnSurf()->Value(par2);
	Standard_Real tolr2;
	ChFi3d_ComputePCurv(C3d,pp1,pp2,st2->ChangePCurve(isfirst2),
			    DStr.Surface(sd2->Surf()).Surface(),
			    P1deb,P2deb,tolapp3d,tolr2);
	tolreached = Max(tolreached,tolr2);
	TopOpeBRepDS_Curve Tcurv2(C3d,tolreached);
	Icl = DStr.AddCurve(Tcurv2);
	regfin.SetCurve(Icl);
	regfin.SetS1(coin->Surf(),0);
	regfin.SetS2(sd2->Surf(),0);
	myRegul.Append(regfin);
	corner->ChangeLastCurve(Icl);
	corner->ChangeLastParameters(P1fin,P2fin);
	corner->ChangeIndexLastPointOnS1(Il1);
	corner->ChangeIndexLastPointOnS2(Il2);
	
	coin->ChangeIndexOfS1(DStr.AddShape(FaCo));
	if(sameparam) coin->ChangeIndexOfS2(0);
	else {
	  coin->ChangeIndexOfS2(DStr.AddShape(FaPiv));
	  coin->ChangeInterferenceOnS2().SetTransition(pctrans);
	}
	corner->SetSolidIndex(st1->SolidIndex());
	
	// then the starting Stripe,
	// ------------------------
	st1->SetCurve(Icf,isfirst1);
	st1->SetIndexPoint(If1,isfirst1,IFaCo1);
	st1->SetIndexPoint(If2,isfirst1,IFaArc1);
	st1->SetParameters(isfirst1,P1deb,P2deb);
	sd1->ChangeVertex(isfirst1,IFaCo1) = Pf1;
	sd1->ChangeVertex(isfirst1,IFaArc1) = Pf2;
	sd1->ChangeInterference(IFaCo1).SetParameter(par1,isfirst1);
	if (IFaCo1 == 2) st1->SetOrientation(TopAbs_REVERSED,isfirst1);
	
	// then the end Stripe,
	// -------------------------
	st2->SetCurve(Icl,isfirst2);
	st2->SetIndexPoint(Il1,isfirst2,IFaCo2);
	st2->SetIndexPoint(Il2,isfirst2,IFaArc2);
	st2->SetParameters(isfirst2,P1fin,P2fin);
	sd2->ChangeVertex(isfirst2,IFaCo2) = Pl1;
	sd2->ChangeVertex(isfirst2,IFaArc2) = Pl2;
	sd2->ChangeInterference(IFaCo2).SetParameter(par2,isfirst2);
	if (IFaCo2 == 2) st2->SetOrientation(TopAbs_REVERSED,isfirst2);
      }
#ifdef OCCT_DEBUG
      ChFi3d_ResultChron(ch , t_t2cornerDS);// result perf update DS 
#endif 
    }
    else {
      //it is necessary to make difference with
      if(!OkinterCC) {
	throw Standard_Failure("TwoCorner : No intersection pc pc");
      }
      Handle(ChFiDS_Stripe) stsam, stdif;
      Handle(ChFiDS_SurfData) sdsam, sddif;
      Standard_Real uintpcsam = 0., uintpcdif = 0.;
      Standard_Integer ifacosam = 0, ifacodif = 0, ifaopsam = 0, ifaopdif = 0;
      Standard_Boolean isfirstsam = Standard_False, isfirstdif = Standard_False;
      if(Stat1 == ChFiDS_OnSame && Stat2 == ChFiDS_OnDiff){
	stsam = st1; sdsam = sd1; uintpcsam = UIntPC1; 
	ifacosam = IFaCo1; ifaopsam = IFaArc1; isfirstsam = isfirst1;
	stdif = st2; sddif = sd2; uintpcdif = UIntPC2; 
	ifacodif = IFaCo2; ifaopdif = IFaArc2; isfirstdif = isfirst2;
      }
      else if(Stat1 == ChFiDS_OnDiff && Stat2 == ChFiDS_OnSame){
	stsam = st2; sdsam = sd2; uintpcsam = UIntPC2; 
	ifacosam = IFaCo2; ifaopsam = IFaArc2; isfirstsam = isfirst2;
	stdif = st1; sddif = sd1; uintpcdif = UIntPC1; 
	ifacodif = IFaCo1; ifaopdif = IFaArc1; isfirstdif = isfirst1;
      }
      else {
	throw Standard_Failure("TwoCorner : Config unknown");
      }
      //It is checked if surface ondiff has a point on arc from the side opposed
      //to the common face and if this arc is connected to the base face  
      //opposed to common face of the surface onsame.
      ChFiDS_CommonPoint& cpopdif = sddif->ChangeVertex(isfirstdif,ifaopdif);
      if(!cpopdif.IsOnArc()) {
	throw Standard_Failure("TwoCorner : No point on restriction on surface OnDiff");
      }
      const TopoDS_Edge& Arcopdif = cpopdif.Arc();
      const TopoDS_Face& Fopsam = TopoDS::Face(DStr.Shape(sdsam->Index(ifaopsam)));
      TopExp_Explorer ex;
      for(ex.Init(Fopsam,TopAbs_EDGE); ex.More(); ex.Next()){
	if(ex.Current().IsSame(Arcopdif)) {
	  break;
	}
	else if(!ex.More()) {
	  throw Standard_Failure("TwoCorner : No common face to loop the contour");
	}
      }
#ifdef OCCT_DEBUG
      ChFi3d_InitChron(ch ); // init perf filling 
#endif 
      Handle(GeomFill_Boundary) Bsam,Bdif,Bfac;
      gp_Pnt2d ppopsam = 
	sdsam->Interference(ifaopsam).PCurveOnSurf()->Value(uintpcsam);
      gp_Pnt2d ppcosam = 
	sdsam->Interference(ifacosam).PCurveOnSurf()->Value(uintpcsam);
      Handle(Geom_Surface) surfsam = DStr.Surface(sdsam->Surf()).Surface();
      Handle(GeomAdaptor_Surface) Hsurfsam = new GeomAdaptor_Surface(surfsam);
      Handle(Geom2d_Curve) pcsurfsam;
      Bsam = ChFi3d_mkbound(Hsurfsam,pcsurfsam,ppopsam,ppcosam,tolapp3d,2.e-4);
      Standard_Real upcopdif = sddif->Interference(ifaopdif).Parameter(isfirstdif);
      gp_Pnt2d ppopdif = 
	sddif->Interference(ifaopdif).PCurveOnSurf()->Value(upcopdif);
      gp_Pnt2d ppcodif = 
	sddif->Interference(ifacodif).PCurveOnSurf()->Value(uintpcdif);
      Handle(Geom_Surface) surfdif = DStr.Surface(sddif->Surf()).Surface();
      Handle(GeomAdaptor_Surface) Hsurfdif = new GeomAdaptor_Surface(surfdif);
      Handle(Geom2d_Curve) pcsurfdif;
      Bdif = ChFi3d_mkbound(Hsurfdif,pcsurfdif,ppcodif,ppopdif,tolapp3d,2.e-4);
      gp_Pnt2d ppfacsam,ppfacdif;
      gp_Pnt PPfacsam,PPfacdif;
      gp_Vec VVfacsam,VVfacdif;
      sdsam->Interference(ifaopsam).PCurveOnFace()->D0(uintpcsam,ppfacsam);
      const Handle(Geom_Curve)& curvopsam = 
	DStr.Curve(sdsam->Interference(ifaopsam).LineIndex()).Curve();
      curvopsam->D1(uintpcsam,PPfacsam,VVfacsam);
      BRepAdaptor_Curve2d PCArcFac(Arcopdif,Fopsam);
      PCArcFac.D0(cpopdif.ParameterOnArc(),ppfacdif);
      //jgv for OCC26173
      BRepAdaptor_Surface SurFopsam(Fopsam);
      if (SurFopsam.IsUClosed())
      {
        Standard_Real Uperiod = SurFopsam.LastUParameter() - SurFopsam.FirstUParameter();
        if (Abs(ppfacsam.X() - ppfacdif.X()) > Uperiod/2)
        {
          if (ppfacdif.X() < ppfacsam.X())
            ppfacdif.SetX(ppfacdif.X() + Uperiod);
          else
            ppfacdif.SetX(ppfacdif.X() - Uperiod);
        }
      }
      //////////////////
      BRepAdaptor_Curve CArcFac(Arcopdif);
      CArcFac.D1(cpopdif.ParameterOnArc(),PPfacdif,VVfacdif);
      Handle(BRepAdaptor_Surface) HBRFopsam = new BRepAdaptor_Surface();
      BRepAdaptor_Surface& BRFopsam = *HBRFopsam;
      BRFopsam.Initialize(Fopsam,Standard_False);
      Handle(Geom2d_Curve) pcFopsam = ChFi3d_BuildPCurve(HBRFopsam,
							 ppfacsam,VVfacsam,
							 ppfacdif,VVfacdif,1);
      Bfac = ChFi3d_mkbound(HBRFopsam,pcFopsam,tolapp3d,2.e-4);
      GeomFill_ConstrainedFilling fil(8,20);
      fil.Init(Bsam,Bdif,Bfac,1);
#if 0
      for(Standard_Integer ib = 0; ib < 4; ib++){
	if(ib == 2) continue;
	fil.CheckCoonsAlgPatch(ib);
	fil.CheckTgteField(ib);
	fil.CheckApprox(ib);
	fil.CheckResult(ib);
      }
#endif
      Handle(Geom_Surface) Surfcoin = fil.Surface();
      TopAbs_Orientation Osurfsam = sdsam->Orientation();
      Handle(Geom2d_Curve) pcnul;
      done = CompleteData(coin,Surfcoin,
			  Hsurfsam,pcsurfsam,
			  HBRFopsam,pcnul,Osurfsam,1,
			  0,0,0,0);
#ifdef OCCT_DEBUG
      ChFi3d_ResultChron(ch , t_remplissage);// result perf filling 
#endif 
      if(!done) throw Standard_Failure("concavites inverted : fail");
#ifdef OCCT_DEBUG
      ChFi3d_InitChron(ch); // init perf update DS
#endif 
      // Update 3 CornerData and the DS
      // ----------------------------------------
      // the corner to start,
      // -----------------------
      Standard_Real P1deb,P2deb,P1fin,P2fin;
      Standard_Integer If1,If2,Il1,Il2,Icf,Icl;
      const ChFiDS_CommonPoint& Pf1 = coin->VertexFirstOnS1();
      ChFiDS_CommonPoint& Pf2 = coin->ChangeVertexFirstOnS2();
      const ChFiDS_CommonPoint& Pl1 = coin->VertexLastOnS1();
      ChFiDS_CommonPoint& Pl2 = coin->ChangeVertexLastOnS2();
      Pf2 = Pl2 = cpopdif;
	
      ChFiDS_Regul regdeb, regfin;
      If1 = ChFi3d_IndexPointInDS(Pf1,DStr);
      If2 = ChFi3d_IndexPointInDS(Pf2,DStr);
      Il1 = ChFi3d_IndexPointInDS(Pl1,DStr);
      Il2 = If2;
	
      gp_Pnt2d pp1,pp2;
      pp1 = coin->InterferenceOnS1().PCurveOnSurf()->
	Value(coin->InterferenceOnS1().FirstParameter());
      pp2 = coin->InterferenceOnS2().PCurveOnSurf()->
	Value(coin->InterferenceOnS2().FirstParameter());
      Handle(Geom_Curve) C3d;
      Standard_Real tolreached;
      ChFi3d_ComputeArete(Pf1,pp1,Pf2,pp2,
			  DStr.Surface(coin->Surf()).Surface(),C3d,
			  corner->ChangeFirstPCurve(),P1deb,P2deb,
			  tolapp3d,tol2d,tolreached,0);
      Standard_Real tolr1;
      Handle(GeomAdaptor_Curve) HC3d = new GeomAdaptor_Curve(C3d);
      ChFi3d_SameParameter(HC3d,pcFopsam,HBRFopsam,tolapp3d,tolr1);
      tolreached = Max(tolreached,tolr1);
      TopOpeBRepDS_Curve Tcurv1(C3d,tolreached);
      Icf = DStr.AddCurve(Tcurv1);
      // place the pcurve on face in the DS
      TopAbs_Orientation OpcFopsam = sdsam->Interference(ifaopsam).Transition();
      Standard_Integer IFopsam = sdsam->Index(ifaopsam);
      if(isfirstsam) OpcFopsam = TopAbs::Reverse(OpcFopsam);
      Handle(TopOpeBRepDS_SurfaceCurveInterference) 
	interf = ChFi3d_FilCurveInDS(Icf,IFopsam,pcFopsam,OpcFopsam);
      DStr.ChangeShapeInterferences(IFopsam).Append(interf);

      regdeb.SetCurve(Icf);
      regdeb.SetS1(coin->Surf(),0);
      regdeb.SetS2(IFopsam,1);
      myRegul.Append(regdeb);
      corner->ChangeFirstCurve(Icf);
      corner->ChangeFirstParameters(P1deb,P2deb);
      corner->ChangeIndexFirstPointOnS1(If1);
      corner->ChangeIndexFirstPointOnS2(If2);
      
      pp1 = coin->InterferenceOnS1().PCurveOnSurf()->
	Value(coin->InterferenceOnS1().LastParameter());
      pp2 = coin->InterferenceOnS2().PCurveOnSurf()->
	Value(coin->InterferenceOnS2().LastParameter());
      ChFi3d_ComputeArete(Pl1,pp1,Pl2,pp2,
			  DStr.Surface(coin->Surf()).Surface(),C3d,
			  corner->ChangeLastPCurve(),P1fin,P2fin,
        tolapp3d,tol2d,tolreached,0);
      Standard_Real tolr2;
      HC3d->Load(C3d);
      ChFi3d_SameParameter(HC3d,pcsurfdif,Hsurfdif,tolapp3d,tolr2);
      tolreached = Max(tolreached,tolr2);
      TopOpeBRepDS_Curve Tcurv2(C3d,tolreached);
      Icl = DStr.AddCurve(Tcurv2);
      regfin.SetCurve(Icl);
      regfin.SetS1(coin->Surf(),0);
      regfin.SetS2(sddif->Surf(),0);
      myRegul.Append(regfin);
      corner->ChangeLastCurve(Icl);
      corner->ChangeLastParameters(P1fin,P2fin);
      corner->ChangeIndexLastPointOnS1(Il1);
      corner->ChangeIndexLastPointOnS2(Il2);
	
      coin->ChangeIndexOfS1(-sdsam->Surf());
      coin->ChangeIndexOfS2(0);

      corner->SetSolidIndex(stsam->SolidIndex());
	
      // then Stripe OnSame
      // ---------------------
      const ChFiDS_FaceInterference& intcoin1 = coin->InterferenceOnS1();
      stsam->SetCurve(intcoin1.LineIndex(),isfirstsam);
      stsam->InDS(isfirstsam); // filDS already works from the corner.
      stsam->ChangePCurve(isfirstsam) = coin->InterferenceOnS1().PCurveOnFace();
      stsam->SetIndexPoint(If1,isfirstsam,ifaopsam);
      stsam->SetIndexPoint(Il1,isfirstsam,ifacosam);
      stsam->SetParameters(isfirstsam,
			   intcoin1.FirstParameter(),
			   intcoin1.LastParameter());
      sdsam->ChangeVertex(isfirstsam,ifaopsam) = Pf1;
      sdsam->ChangeVertex(isfirstsam,ifacosam) = Pl1;
      sdsam->ChangeInterferenceOnS1().SetParameter(uintpcsam,isfirstsam);
      sdsam->ChangeInterferenceOnS2().SetParameter(uintpcsam,isfirstsam);
      if (ifaopsam == 2) stsam->SetOrientation(TopAbs_REVERSED,isfirstsam);
	
      // then Stripe OnDiff
      // ---------------------
      stdif->SetCurve(Icl,isfirstdif);
      stdif->ChangePCurve(isfirstdif) = pcsurfdif;
      stdif->SetIndexPoint(Il2,isfirstdif,ifaopdif);
      stdif->SetIndexPoint(Il1,isfirstdif,ifacodif);
      stdif->SetParameters(isfirstdif,P1fin,P2fin);
      sddif->ChangeVertex(isfirstdif,ifaopdif) = Pl2;
      sddif->ChangeVertex(isfirstdif,ifacodif) = Pl1;
      sddif->ChangeInterference(ifacodif).SetParameter(uintpcdif,isfirstdif);
      if (ifaopdif == 1) stdif->SetOrientation(TopAbs_REVERSED,isfirstdif);
#ifdef OCCT_DEBUG
      ChFi3d_ResultChron(ch , t_t2cornerDS);// result perf update DS 
#endif 
    }
    if(!myEVIMap.IsBound(Vtx)){
      TColStd_ListOfInteger li;
      myEVIMap.Bind(Vtx,li);
    }
    myEVIMap.ChangeFind(Vtx).Append(coin->Surf());
    myListStripe.Append(corner);
  }
}  

