// File:	TopOpeBRepBuild_Builder_1.cxx
// Created:	Thu Oct  7 09:38:29 1999
// Author:	Peter KURNEV
//		<pkv@irinox.nnov.matra-dtv.fr>

#include <TopOpeBRepBuild_Builder.ixx>

#include <BRepTools.hxx>
#include <BRep_Builder.hxx>

#include <TopExp.hxx>

#include <TopoDS.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Wire.hxx>

#include <TopTools_MapOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <TopTools_MapIteratorOfMapOfShape.hxx>
#include <TopTools_IndexedMapOfShape.hxx>

#include <TopOpeBRepBuild_PaveSet.hxx>
#include <TopOpeBRepBuild_GTool.hxx>
#include <TopOpeBRepBuild_Pave.hxx>
#include <TopOpeBRepBuild_Loop.hxx>
#include <TopOpeBRepBuild_EdgeBuilder.hxx>
#include <TopOpeBRepBuild_ListOfListOfLoop.hxx>
#include <TopOpeBRepBuild_Tools.hxx>
#include <TopOpeBRepBuild_GTopo.hxx>

#include <TopOpeBRepDS_DataMapOfShapeState.hxx>
#include <TopOpeBRepDS_DataMapIteratorOfDataMapOfShapeState.hxx>
#include <TopOpeBRepDS_Interference.hxx>
#include <TopOpeBRepDS_ListOfInterference.hxx>
#include <TopOpeBRepDS_ListIteratorOfListOfInterference.hxx>
#include <TopOpeBRepDS_IndexedDataMapOfShapeWithState.hxx>
#include <TopOpeBRepDS_ShapeWithState.hxx>
#include <TopOpeBRepDS_DataStructure.hxx>
#include <BRep_Tool.hxx>
#include <TopOpeBRepDS_ListOfShapeOn1State.hxx>
#include <Geom_Curve.hxx>
#include <Precision.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <TopTools_DataMapOfShapeListOfInteger.hxx>
#include <TColStd_ListIteratorOfListOfInteger.hxx>

//define parameter division number as 10*e^(-PI) = 0.43213918
const Standard_Real PAR_T = 0.43213918;

static TopAbs_State ClassifyEdgeToSolidByOnePoint(const TopoDS_Edge& E,
						  TopOpeBRepTool_ShapeClassifier& SC);

//=======================================================================
//         : Definition the States of Shape's Entities for an Object
//         : and a Tool.                    Thu Oct  7 09:38:29 1999
//=======================================================================

static TopTools_IndexedMapOfShape processedEdges;
static TopTools_IndexedMapOfShape theUsedVertexMap;
static TopTools_MapOfShape theUnkStateVer;

Standard_IMPORT Standard_Boolean GLOBAL_faces2d;

//modified by NIZNHY-PKV Mon Dec 16 11:38:55 2002 f
//=======================================================================
//function : Destroy
//purpose  : 
//=======================================================================
void TopOpeBRepBuild_Builder1::Destroy()
{
  processedEdges.Clear();
  theUsedVertexMap.Clear();
  theUnkStateVer.Clear();
}
//modified by NIZNHY-PKV Mon Dec 16 11:38:59 2002 t

//=======================================================================
//function : PerformShapeWithStates
//purpose  : 
//=======================================================================
  void TopOpeBRepBuild_Builder1::PerformShapeWithStates()
{
  theUsedVertexMap.Clear();
  theUnkStateVer.Clear();
  myDataStructure -> ChangeDS().ChangeMapOfShapeWithStateObj().Clear();
  myDataStructure -> ChangeDS().ChangeMapOfShapeWithStateTool().Clear();
    //modified by NIZHNY-MZV  Mon Feb 21 13:30:05 2000
  //process section curves 
  Standard_Integer i, nbC = myDataStructure -> DS().NbCurves();
  for(i = 1; i <= nbC; i++) {
    TopTools_ListOfShape& LSE = ChangeNewEdges(i);
    TopTools_ListIteratorOfListOfShape it(LSE);
    for(; it.More(); it.Next())  {
      const TopoDS_Shape& E = it.Value();
      TopoDS_Vertex Vf, Vl;
      TopExp::Vertices(TopoDS::Edge(E), Vf, Vl);
      theUsedVertexMap.Add(Vf);
      theUsedVertexMap.Add(Vl);
    }
  }
  
  //process section edges
  const TopOpeBRepDS_DataStructure& BDS = myDataStructure->DS();
  Standard_Integer n = BDS.NbSectionEdges();
  for (i = 1; i <= n; i++) { 
    TopTools_ListIteratorOfListOfShape anIt;
    const TopoDS_Edge& E = TopoDS::Edge(BDS.SectionEdge(i));
    if(E.IsNull()) continue;
    
    const TopTools_ListOfShape& SplitsON = Splits(E, TopAbs_ON);
    anIt.Initialize (SplitsON);
    for (; anIt.More(); anIt.Next()) {
      TopoDS_Shape aNewEdge=anIt.Value();
      TopoDS_Vertex Vf, Vl;
      TopExp::Vertices(TopoDS::Edge(aNewEdge), Vf, Vl);
      theUsedVertexMap.Add(Vf);
      theUsedVertexMap.Add(Vl);
    }
      
      // IN
    const TopTools_ListOfShape& SplitsIN = Splits(E, TopAbs_IN);
    anIt.Initialize (SplitsIN);
    for (; anIt.More(); anIt.Next()) {
      TopoDS_Shape aNewEdge=anIt.Value();
      TopoDS_Vertex Vf, Vl;
      TopExp::Vertices(TopoDS::Edge(aNewEdge), Vf, Vl);
      theUsedVertexMap.Add(Vf);
      theUsedVertexMap.Add(Vl);
    }
      
    // OUT
    const TopTools_ListOfShape& SplitsOUT = Splits(E, TopAbs_OUT);
    anIt.Initialize (SplitsOUT);
    for (; anIt.More(); anIt.Next()) {
      TopoDS_Shape aNewEdge=anIt.Value();
      TopoDS_Vertex Vf, Vl;
      TopExp::Vertices(TopoDS::Edge(aNewEdge), Vf, Vl);
      theUsedVertexMap.Add(Vf);
      theUsedVertexMap.Add(Vl);
    } 
  } 

  //modified by NIZHNY-MZV  Tue Apr 11 17:32:05 2000
  //1) Add both arguments to facilitate the search
  TopOpeBRepDS_ShapeWithState aShapeWithState;
  TopOpeBRepDS_DataStructure& aDataStructure=myDataStructure->ChangeDS();
  
  TopOpeBRepDS_IndexedDataMapOfShapeWithState& aMapOfShapeWithStateObj=
    aDataStructure.ChangeMapOfShapeWithStateObj();
  TopOpeBRepDS_IndexedDataMapOfShapeWithState& aMapOfShapeWithStateTool=
    aDataStructure.ChangeMapOfShapeWithStateTool();

  aMapOfShapeWithStateObj.Add(myShape1, aShapeWithState);
  aMapOfShapeWithStateTool.Add(myShape2, aShapeWithState);

  //2) Add all rejected shapes as OUT

  TopTools_IndexedMapOfShape& aMapOfRejectedShapesObj=
    aDataStructure.ChangeMapOfRejectedShapesObj();
  TopTools_IndexedMapOfShape& aMapOfRejectedShapesTool=
    aDataStructure.ChangeMapOfRejectedShapesTool();

  aShapeWithState.SetIsSplitted (Standard_False);
  aShapeWithState.SetState (TopAbs_OUT);
 
  Standard_Integer iW, j, nW, nE, 
                   nRSObj = aMapOfRejectedShapesObj.Extent(), 
                   nRSTool = aMapOfRejectedShapesTool.Extent();
  
  for(i = 1; i <= nRSObj; i++) {
    const TopoDS_Shape& aFace = aMapOfRejectedShapesObj(i);
    if(aFace.ShapeType() != TopAbs_FACE)
      continue; 
    TopTools_IndexedMapOfShape aWiresMap;
    
    TopExp::MapShapes (aFace, TopAbs_WIRE, aWiresMap);
    nW=aWiresMap.Extent ();
    for (iW=1; iW<=nW; iW++) {
      const TopoDS_Shape& aWire=aWiresMap(iW);
      //
      TopTools_IndexedMapOfShape anEdgesMap;
      TopExp::MapShapes (aWire, TopAbs_EDGE, anEdgesMap);
      nE=anEdgesMap.Extent ();
      for (j=1; j<=nE; j++) 
	aMapOfShapeWithStateObj.Add(anEdgesMap(j), aShapeWithState); // add edge

      aMapOfShapeWithStateObj.Add(aWire, aShapeWithState); // add wire 
    }
    aMapOfShapeWithStateObj.Add(aFace, aShapeWithState); // add face
  }

  for(i = 1; i <= nRSTool; i++) {
    const TopoDS_Shape& aFace = aMapOfRejectedShapesTool(i);
    //modified by NIZHNY-MZV  Wed Apr  5 10:27:18 2000
    if(aFace.ShapeType() != TopAbs_FACE)
      continue; 
    TopTools_IndexedMapOfShape aWiresMap;
    TopExp::MapShapes (aFace, TopAbs_WIRE, aWiresMap);
    nW=aWiresMap.Extent ();
    for (iW=1; iW<=nW; iW++) {
      const TopoDS_Shape& aWire=aWiresMap(iW);
      //
      TopTools_IndexedMapOfShape anEdgesMap;
      TopExp::MapShapes (aWire, TopAbs_EDGE, anEdgesMap);
      nE=anEdgesMap.Extent ();
      for (j=1; j<=nE; j++) 
	aMapOfShapeWithStateTool.Add(anEdgesMap(j), aShapeWithState); // add edge

      aMapOfShapeWithStateTool.Add(aWire, aShapeWithState); // add wire 
    }
    aMapOfShapeWithStateTool.Add(aFace, aShapeWithState); // add face
  }
 
  PerformShapeWithStates (myShape1, myShape2);
  processedEdges.Clear();
  PerformShapeWithStates (myShape2, myShape1);
  processedEdges.Clear();
  // Print Block
//  printf(" ..::PerformShapeWithStates() [Dump is off]\n");
  
/*  printf(" ..::PerformShapeWithStates() [Dump is on]\n");
  
  TopOpeBRepDS_DataStructure& aDS= myDataStructure-> ChangeDS();
  
  TopOpeBRepDS_IndexedDataMapOfShapeWithState& aMapOfShapeWithStateObj=
    aDS.ChangeMapOfShapeWithStateObj();

  TopOpeBRepDS_IndexedDataMapOfShapeWithState& aMapOfShapeWithStateTool=
    aDS.ChangeMapOfShapeWithStateTool();
 
  TopOpeBRepBuild_Tools::DumpMapOfShapeWithState(0, aMapOfShapeWithStateObj);
  TopOpeBRepBuild_Tools::DumpMapOfShapeWithState(1, aMapOfShapeWithStateTool);
*/  
 
  // Phase#2 Phase ON
//  PerformOn2D ();
}

//=======================================================================
//function :PerformShapeWithStates
//purpose  : 
//=======================================================================
  void TopOpeBRepBuild_Builder1::PerformShapeWithStates (const TopoDS_Shape& anObj, 
							const TopoDS_Shape& aReference)
{
  myShapeClassifier.SetReference(aReference);
  TopOpeBRepDS_DataStructure& aDS= myDataStructure-> ChangeDS();
  // Get aMapOfShapeWithState for Obj
  Standard_Boolean aFlag;
  TopOpeBRepDS_IndexedDataMapOfShapeWithState& aMapOfShapeWithState=
    aDS.ChangeMapOfShapeWithState(anObj, aFlag); 
  if (!aFlag) return;
  //
  Standard_Integer i, j, k, nS, nF, nE;
  
  TopTools_IndexedMapOfShape aFacesMap, aFacesWithInterferencesMap, aFacesToRestMap;
  TopOpeBRepDS_DataMapOfShapeState aSplFacesState;
  
  TopTools_IndexedMapOfShape aShellsMap;
  TopExp::MapShapes(anObj, TopAbs_SHELL, aShellsMap);

  nS=aShellsMap.Extent();
  for (i=1; i<=nS; i++) {
    const TopoDS_Shape& aShell = aShellsMap(i);

    if (aMapOfShapeWithState.Contains (aShell)) continue;

    else  if (!myDataStructure -> HasShape(aShell)) {
      // Shell has no interference. 
      // So, define its state and push into the Map as is.// A.1
      TopOpeBRepBuild_Tools::FindStateThroughVertex (aShell, myShapeClassifier,
                                                     aMapOfShapeWithState, theUnkStateVer);
      continue;
    }

    else {// A.2
      // Shell has interference. Try to separate it into FacesToRest and InterferredFace
      aFacesMap.Clear();
      aFacesWithInterferencesMap.Clear();
      aFacesToRestMap.Clear();
      aSplFacesState.Clear();
      
      TopExp::MapShapes (aShell, TopAbs_FACE, aFacesMap);
      nF=aFacesMap.Extent();
      for (j=1; j<=nF; j++) {
	const TopoDS_Shape& aFace = aFacesMap(j);
	
	if (aMapOfShapeWithState.Contains (aFace)) {
	 
	  // if the face is known, its edges are also known.
	  // We just insert this info. into aSplFacesState in order to 
	  // propagate the state for faces with unknown states.
	  TopTools_IndexedMapOfShape anEdgesMap;
	  TopExp::MapShapes (aFace, TopAbs_EDGE, anEdgesMap);
	  nE=anEdgesMap.Extent();
	  for (k=1; k<=nE; k++) {
	    const TopoDS_Shape& anEdge=anEdgesMap(k);
	    const TopOpeBRepDS_ShapeWithState& aSWS=
	      aMapOfShapeWithState.FindFromKey(anEdge);
	    TopAbs_State aState=aSWS.State();
	    aSplFacesState.Bind (anEdge, aState);
	  }
	  continue;
	} 
	else if (myDataStructure -> HasShape(aFace)) 	
	  aFacesWithInterferencesMap.Add (aFace);  
	else {	
	  aFacesToRestMap.Add (aFace);
	}
      } // ... next Face
      // work with aFacesWithInterferencesMap
      PerformFacesWithStates (anObj, aFacesWithInterferencesMap, aSplFacesState);
			      
      // Propagate the States  for all unknown faces from aFacesToRestMap  
      TopTools_MapOfShape anUnkStateEdge;
      TopOpeBRepBuild_Tools::PropagateState (aSplFacesState,aFacesToRestMap,
					     TopAbs_EDGE, TopAbs_FACE, myShapeClassifier,
                                             aMapOfShapeWithState, anUnkStateEdge);
      ///// Propagate on WIres from aFacesToRestMap  
      TopOpeBRepBuild_Tools::PropagateStateForWires (aFacesToRestMap, aMapOfShapeWithState);
    } // end of else A.2
  } // next Shell 
}

//=======================================================================
//function :PerformFacesWithStates
//purpose  :
//=======================================================================
  void TopOpeBRepBuild_Builder1::PerformFacesWithStates (const TopoDS_Shape& anObj,
							const TopTools_IndexedMapOfShape& aFacesWithInterferencesMap,
							TopOpeBRepDS_DataMapOfShapeState& aSplFacesState)
{
  TopOpeBRepDS_DataStructure& aDS= myDataStructure-> ChangeDS();
  // Get aMapOfShapeWithState for Obj
  Standard_Boolean aFlag;
  TopOpeBRepDS_IndexedDataMapOfShapeWithState& aMapOfShapeWithState=aDS.ChangeMapOfShapeWithState(anObj, aFlag); 
  if (!aFlag) return;
  //

  Standard_Integer i, j, k, nF, nW, nE;
  
  nF=aFacesWithInterferencesMap.Extent();
  
  for (i=1; i<=nF; i++) {
    TopTools_IndexedMapOfShape anEdgesToSplitMap, anEdgesToRestMap;
    
    const TopoDS_Shape& aFace = aFacesWithInterferencesMap(i);
    
    TopTools_IndexedMapOfShape aWireMap;
    TopExp::MapShapes (aFace, TopAbs_WIRE, aWireMap);
    nW=aWireMap.Extent();
    for (j=1; j<=nW; j++) {
      const TopoDS_Shape& aWire=aWireMap(j);
      
      if (!myDataStructure -> HasShape(aWire)) {
	// Wire has no interference. 
	// So, define its state and push into the Map as is.
	TopOpeBRepBuild_Tools::FindStateThroughVertex (aWire, myShapeClassifier,
                                                       aMapOfShapeWithState, theUnkStateVer);
	continue;
      }
      
      else {
	// Wire has an interferences 
	TopTools_IndexedMapOfShape anEdgeMap;
	TopExp::MapShapes (aWire, TopAbs_EDGE, anEdgeMap);
	nE=anEdgeMap.Extent ();
	for (k=1; k<=nE; k++) {
	  const TopoDS_Shape& anEdge=anEdgeMap(k);

	  if (myDataStructure -> HasShape(anEdge)) {
	    anEdgesToSplitMap.Add(anEdge);
	  }
	  else {
	    anEdgesToRestMap.Add(anEdge);
	  }
	}
	
	// split edges and define the states for all edges and parts of edges
	StatusEdgesToSplit (anObj, anEdgesToSplitMap, anEdgesToRestMap);
      
	////// After StatusEdgesToSplit we can find  the status of each Rest Edge
	////// in aMapOfShapeWithState. So we can insert this info. into 
	////// aSplFacesState in order to propagate the state for faces.
	nE=anEdgesToRestMap.Extent();
	for (k=1; k<=nE; k++) {
	  const TopoDS_Shape anEdge=anEdgesToRestMap(k);
	  if (aMapOfShapeWithState.Contains (anEdge)) {
	    const TopOpeBRepDS_ShapeWithState& aSWS=aMapOfShapeWithState.FindFromKey(anEdge);
	    TopAbs_State aState=aSWS.State();
	    aSplFacesState.Bind (anEdge, aState);  
	  }
	}
      } //end of else {// Wire has an interferences 
    } // next Wire
  } // next interferred Face ... for (i=1; i<=nF; i++) ...
}

//=======================================================================
//function :StatusEdgesToSplit
//purpose  : 
//=======================================================================
  void TopOpeBRepBuild_Builder1::StatusEdgesToSplit (const TopoDS_Shape& anObj,
						    const TopTools_IndexedMapOfShape& anEdgesToSplitMap,
						    const TopTools_IndexedMapOfShape& anEdgesToRestMap)
{
 

  TopOpeBRepDS_DataStructure& aDS= myDataStructure-> ChangeDS();
  // Get aMapOfShapeWithState for Obj
  Standard_Boolean aFlag;
  TopOpeBRepDS_IndexedDataMapOfShapeWithState& aMapOfShapeWithState=aDS.ChangeMapOfShapeWithState(anObj, aFlag); 
  if (!aFlag) return;
  //

  Standard_Integer i, nE=anEdgesToSplitMap.Extent();
  if (!nE) return;

  TopOpeBRepDS_DataMapOfShapeState aSplEdgesState;
  TopTools_ListIteratorOfListOfShape anIt;
  TopAbs_State aState;
 
  for (i=1; i<=nE; i++) {
    const TopoDS_Shape& anEdge=anEdgesToSplitMap(i);
    
    if(processedEdges.Contains(anEdge)) {
      if (aMapOfShapeWithState.Contains(anEdge)) {
	const TopOpeBRepDS_ShapeWithState& aSWS=
	  aMapOfShapeWithState.FindFromKey(anEdge);
	if (aSWS.IsSplitted()) {

	  const TopTools_ListOfShape& SplitsON=aSWS.Part(TopAbs_ON);
	  anIt.Initialize (SplitsON);
	  for (; anIt.More(); anIt.Next()) 
	    aSplEdgesState.Bind(anIt.Value(), TopAbs_ON);
	  
	  const TopTools_ListOfShape& SplitsOUT=aSWS.Part(TopAbs_OUT);
	  anIt.Initialize (SplitsOUT);
	  for (; anIt.More(); anIt.Next()) 
	    aSplEdgesState.Bind(anIt.Value(), TopAbs_OUT);
	  
	  const TopTools_ListOfShape& SplitsIN=aSWS.Part(TopAbs_IN);
	  anIt.Initialize (SplitsIN);
	  for (; anIt.More(); anIt.Next()) 
	    aSplEdgesState.Bind(anIt.Value(), TopAbs_IN);
	  
	}
      }
      continue;
    }

    processedEdges.Add(anEdge);
    
    TopOpeBRepDS_ShapeWithState aShapeWithState;
    
    //  if IsSplit - it is the case of edges from SameDomain faces
    Standard_Boolean IsSplitON = IsSplit(anEdge, TopAbs_ON);
    if(IsSplitON) {
      // ON
      const TopTools_ListOfShape& SplitsON = Splits(anEdge, TopAbs_ON);
      anIt.Initialize (SplitsON);
      for (; anIt.More(); anIt.Next()) {
	TopoDS_Shape aNewEdge=anIt.Value();
	aNewEdge.Orientation (anEdge.Orientation());
	aShapeWithState.AddPart (aNewEdge, TopAbs_ON);
	aSplEdgesState.Bind(anIt.Value(), TopAbs_ON);
      }
      
      // IN
      const TopTools_ListOfShape& SplitsIN = Splits(anEdge, TopAbs_IN);
      anIt.Initialize (SplitsIN);
      for (; anIt.More(); anIt.Next()) {
	TopoDS_Shape aNewEdge=anIt.Value();
	aNewEdge.Orientation (anEdge.Orientation());
	aShapeWithState.AddPart (aNewEdge, TopAbs_IN);
	aSplEdgesState.Bind(anIt.Value(), TopAbs_IN);
      }
      
      // OUT
      const TopTools_ListOfShape& SplitsOUT = Splits(anEdge, TopAbs_OUT);
      anIt.Initialize (SplitsOUT);
      for (; anIt.More(); anIt.Next()) {
	TopoDS_Shape aNewEdge=anIt.Value();
	aNewEdge.Orientation (anEdge.Orientation());
	aShapeWithState.AddPart (aNewEdge, TopAbs_OUT);
	aSplEdgesState.Bind(anIt.Value(), TopAbs_OUT);
      }
      
      aShapeWithState.SetIsSplitted(Standard_True);
      aMapOfShapeWithState.Add(anEdge, aShapeWithState);
      continue;
    }
    
    //  Attempt to split the Edge (for all other edges (from non SameDomain Faces))
    TopOpeBRepDS_DataMapOfShapeState aDataMapOfShapeState;
    TopTools_ListOfShape aLNew;

    Standard_Boolean oldState = GLOBAL_faces2d;

    GLOBAL_faces2d = Standard_True;
    SplitEdge (anEdge, aLNew, aDataMapOfShapeState);
    GLOBAL_faces2d = oldState;

    //
    if (!aLNew.Extent()) {
      // * It means that whole Edge is IN (see SplitEdge(...) at line 
      // G1=TopOpeBRepBuild_GTool::GFusSame(tf,tf); Operation  Fuse 
      // loses all parts of the Edge with IN  state, but  we  need 
      // to have all parts. So, we have to rest the Edge as is ...
      // ** But the edge itself will have UNKNOWN state and one split Part with state =IN.
      TopoDS_Vertex Vf, Vl;
      TopExp::Vertices(TopoDS::Edge(anEdge), Vf, Vl);
      
      Standard_Boolean HasSDV1 = myDataStructure->HasSameDomain(Vf);
      Standard_Boolean HasSDV2 = myDataStructure->HasSameDomain(Vl);

      TopoDS_Edge aNewEdge = TopoDS::Edge(anEdge);

      //if edge has SD edges , it is error because it must be processed in SplitSectionEdges
      //but if we here we don't do anything with it
      if(myDataStructure -> HasSameDomain(aNewEdge)) {
	HasSDV1 = Standard_False;
	HasSDV2 = Standard_False;
      }
      //if vertices has SD we must update edge, so we copy it
      if(HasSDV1 || HasSDV2) {
	TopoDS_Shape EOR = anEdge; 
	EOR.Orientation(TopAbs_FORWARD);

	Standard_Real ParF = BRep_Tool::Parameter(Vf, TopoDS::Edge(EOR));
	Standard_Real ParL = BRep_Tool::Parameter(Vl, TopoDS::Edge(EOR));
	myBuildTool.CopyEdge (EOR, aNewEdge);

	if (HasSDV1) { // on prend le vertex reference de V
	  Standard_Integer iref = myDataStructure->SameDomainReference(Vf);
	  Vf = TopoDS::Vertex(myDataStructure->Shape(iref));
	  Vf.Orientation(TopAbs_FORWARD);
	}
     
	if (HasSDV2) { // on prend le vertex reference de V
	  Standard_Integer iref = myDataStructure->SameDomainReference(Vl);
	  Vl = TopoDS::Vertex(myDataStructure->Shape(iref));
	  Vl.Orientation(TopAbs_REVERSED);
	}
	Standard_Boolean bitclosed = Vf.IsSame(Vl);
	aNewEdge.Closed(bitclosed);
      
	myBuildTool.AddEdgeVertex (aNewEdge, Vf);
	myBuildTool.Parameter     (aNewEdge, Vf, ParF);
	
	myBuildTool.AddEdgeVertex (aNewEdge, Vl);
	myBuildTool.Parameter     (aNewEdge, Vl, ParL);
	
	aNewEdge.Orientation (anEdge.Orientation()); 
      }

      aState= ClassifyEdgeToSolidByOnePoint(aNewEdge, myShapeClassifier);
      aShapeWithState.SetIsSplitted (Standard_True);

      aShapeWithState.AddPart (aNewEdge, aState);
      aSplEdgesState.Bind(aNewEdge, aState);

      TopExp::Vertices(aNewEdge, Vf, Vl);
      theUsedVertexMap.Add(Vf);
      theUsedVertexMap.Add(Vl);
      if (!BRep_Tool::Degenerated(TopoDS::Edge(aNewEdge))) {
        // MSV: it may be the case when an edge has one state but its vertex
        //      has another state. We should clarify this to avoid incorrect
        //      propagation of state.
        myShapeClassifier.StateP3DReference(BRep_Tool::Pnt(Vf));
        if (myShapeClassifier.State() != aState && myShapeClassifier.State() != TopAbs_ON)
          theUnkStateVer.Add(Vf);
        if (!Vf.IsSame(Vl)) {
          myShapeClassifier.StateP3DReference(BRep_Tool::Pnt(Vl));
          if (myShapeClassifier.State() != aState && myShapeClassifier.State() != TopAbs_ON)
            theUnkStateVer.Add(Vl);
        }
      }
    }
    else {
      // Usual case. The Edge was splitted onto several parts: 
      TopTools_ListIteratorOfListOfShape aLIt(aLNew);
      for (; aLIt.More(); aLIt.Next()) {
	const TopoDS_Shape& aS = aLIt.Value();
	aState = aDataMapOfShapeState(aS);
	////////////////////////////////////////////////////////////////////////////
	// **  When aState==TopAbs_IN it is not evidence that it is realy so.
	// There are some cases when JYL does not define ON parts completely.
	// So,  as we want to have right states,  we have to do it ourselves.  
	// PKV Mon 25 Oct 1999
	Standard_Boolean isdegen = BRep_Tool::Degenerated(TopoDS::Edge(aS));
	//if edge is degenerated we trust that it have IN state without classify 

	if (aState==TopAbs_IN && !isdegen)  
	  aState= ClassifyEdgeToSolidByOnePoint(TopoDS::Edge(aS), myShapeClassifier);

	////////////////////////////////////////////////////////////////////////////
	aShapeWithState.AddPart (aS, aState);
	aShapeWithState.SetIsSplitted (Standard_True);
	  
	aSplEdgesState.Bind(aS, aState);
	TopoDS_Vertex Vf, Vl;
	TopExp::Vertices(TopoDS::Edge(aS), Vf, Vl);
	theUsedVertexMap.Add(Vf);
	theUsedVertexMap.Add(Vl);
        if (!isdegen) {
          // MSV: clarify state of vertices (see my above comment)
          myShapeClassifier.StateP3DReference(BRep_Tool::Pnt(Vf));
          if (myShapeClassifier.State() != aState && myShapeClassifier.State() != TopAbs_ON)
            theUnkStateVer.Add(Vf);
          if (!Vf.IsSame(Vl)) {
            myShapeClassifier.StateP3DReference(BRep_Tool::Pnt(Vl));
            if (myShapeClassifier.State() != aState && myShapeClassifier.State() != TopAbs_ON)
              theUnkStateVer.Add(Vl);
          }
        }
      }
    }

    const TopTools_ListOfShape& EspON = aShapeWithState.Part(TopAbs_ON);

    Standard_Integer nON = EspON.Extent();
    if(!IsSplitON  && nON) {
      TopOpeBRepDS_ListOfShapeOn1State ONspl;
      TopTools_ListOfShape& lON = ONspl.ChangeListOnState();
      lON.Assign(EspON);
      ONspl.Split(Standard_True);
      mySplitON.Bind(anEdge, ONspl);
      myDataStructure -> ChangeDS().AddSectionEdge(TopoDS::Edge(anEdge)); 
    }

    aMapOfShapeWithState.Add(anEdge, aShapeWithState);
  } // end  for (i=1; i<=nE; i++) 

  nE=anEdgesToRestMap.Extent();
  for (i=1; i<=nE; i++) {
    const TopoDS_Shape& anEdge=anEdgesToRestMap.FindKey(i);
    if (aMapOfShapeWithState.Contains (anEdge)) {
      const TopOpeBRepDS_ShapeWithState& aSWS= 
	aMapOfShapeWithState.FindFromKey(anEdge);
      if (!aSWS.IsSplitted()) {
	// just in case
	aState=aSWS.State();
	aSplEdgesState.Bind (anEdge, aState);
	continue;
      }
    }
  }

  if (nE)
    //  Propagate the status for anEdgesToRestMap edges 
    TopOpeBRepBuild_Tools::PropagateState (aSplEdgesState, anEdgesToRestMap,
                                           TopAbs_VERTEX,  TopAbs_EDGE, myShapeClassifier,
                                           aMapOfShapeWithState, theUnkStateVer);

}



//=======================================================================
//function : SplitEdge
//purpose  : 
//=======================================================================
  void TopOpeBRepBuild_Builder1::SplitEdge (const TopoDS_Shape& anEdge, 
                                           TopTools_ListOfShape& aLNew,
					   TopOpeBRepDS_DataMapOfShapeState& aDataMapOfShapeState)
{
  Standard_Real aPar1, aPar2;
  TopAbs_Orientation anOr1, anOr2;

  // Attention! If you didn't do the orientation of the Edge =FORWARD,
  // the GFillPointTopologyPVS() method will give you a garbage!  
  TopoDS_Shape EdgeF=anEdge; 
  EdgeF.Orientation(TopAbs_FORWARD);
  
  // Make a PaveSet PVS on edge EF
  TopOpeBRepBuild_PaveSet PVS (EdgeF);
  TopOpeBRepBuild_GTopo G1;
  TopAbs_ShapeEnum tf = TopAbs_FACE;
  G1=TopOpeBRepBuild_GTool::GFusSame(tf,tf); 
  myEdgeReference = TopoDS::Edge(EdgeF);

  GFillPointTopologyPVS(EdgeF, G1, PVS);

  PVS.InitLoop();

  //firstly we detect paves with equal params

  // MSV Oct 23, 2001:
  //  Add Paves to a standard list rather than to a PaveSet to avoid
  //  possible sequence disturbance in InitLoop.
  //  Check points for equality in both 3d and 1d spaces using maximum 
  //  of tolerances of the edge and compared vertices, in 1d using resolution
  //  on edge from that value

  TopOpeBRepBuild_ListOfPave aPVSlist;
  TopTools_DataMapOfShapeListOfInteger aVerOriMap;

  BRepAdaptor_Curve aCurveAdaptor(TopoDS::Edge(anEdge));
  Standard_Real tolEdge = BRep_Tool::Tolerance(TopoDS::Edge(anEdge));

  while (PVS.MoreLoop()) {
    Handle(TopOpeBRepBuild_Pave) aPave1=Handle(TopOpeBRepBuild_Pave)::DownCast(PVS.Loop());
    const TopoDS_Vertex& aV1= TopoDS::Vertex(aPave1->Vertex());
    aPar1    = aPave1->Parameter();
    
    PVS.NextLoop();
    if (!PVS.MoreLoop()) {
      aPVSlist.Append(aPave1);
      break;
    }
      
    Handle(TopOpeBRepBuild_Pave) aPave2=Handle(TopOpeBRepBuild_Pave)::DownCast(PVS.Loop());
    const TopoDS_Vertex& aV2= TopoDS::Vertex(aPave2->Vertex());
    aPar2    = aPave2->Parameter();

    Standard_Real tolV1 = BRep_Tool::Tolerance(aV1);
    Standard_Real tolV2 = BRep_Tool::Tolerance(aV2);
    Standard_Real tolMax = Max(tolEdge,Max(tolV1,tolV2));
    Standard_Real resol = aCurveAdaptor.Resolution(tolMax);
    Standard_Real delta = Abs(aPar1 - aPar2);

    if(delta < resol) {
      Standard_Real dist = BRep_Tool::Pnt(aV1).Distance(BRep_Tool::Pnt(aV2));
      if (dist < tolMax || delta < Precision::PConfusion()) {

        TopOpeBRepDS_Kind IntType1 = aPave1 -> InterferenceType();
        Standard_Boolean Int3d1 = (IntType1 == TopOpeBRepDS_FACE);
        Standard_Boolean HasSDV1 = myDataStructure->HasSameDomain(aV1);
        Standard_Boolean HasSDV2 = myDataStructure->HasSameDomain(aV2);
        Standard_Boolean UsedV1 = theUsedVertexMap.Contains(aV1);
        Standard_Boolean UsedV2 = theUsedVertexMap.Contains(aV2);

        Standard_Boolean takeFirst = Standard_True;
        if(HasSDV1)      ;
        else if(HasSDV2) takeFirst = Standard_False;
        else if(UsedV1)  ;
        else if(UsedV2)  takeFirst = Standard_False;
        else if(Int3d1)  ;
        else             takeFirst = Standard_False;
        TopoDS_Shape aVer;
        Standard_Boolean HasSDV;
        TopAbs_Orientation anOriOpp;
        if (takeFirst) {
          aPVSlist.Append(aPave1);
          aVer = aV1; HasSDV = HasSDV1; anOriOpp = aV2.Orientation();
        }
        else {
          aPVSlist.Append(aPave2);
          aVer = aV2; HasSDV = HasSDV2; anOriOpp = aV1.Orientation();
        }

        if (aV1.Orientation() != aV2.Orientation()) {
          // MSV: save orientation of removed vertex
          TColStd_ListOfInteger thelist;
          if (!aVerOriMap.IsBound(aVer)) aVerOriMap.Bind(aVer, thelist);
          TColStd_ListOfInteger& anOriList = aVerOriMap(aVer);
          anOriList.Append(takeFirst);
          anOriList.Append(anOriOpp);
          // mark this vertex as having unknown state
          if (HasSDV) {
            Standard_Integer iref = myDataStructure->SameDomainReference(aVer);
            aVer = myDataStructure->Shape(iref);
          }
          theUnkStateVer.Add(aVer);
        }

        PVS.NextLoop();
        continue;
      }
    }
    aPVSlist.Append(aPave1);
  }

  TopOpeBRepBuild_ListIteratorOfListOfPave aPVSit(aPVSlist);
  while (aPVSit.More()) {
    Handle(TopOpeBRepBuild_Pave) aPave1 = aPVSit.Value();
    TopoDS_Shape aV1= aPave1->Vertex();
    aV1.Orientation(TopAbs_FORWARD);
    aPar1    = aPave1->Parameter();
    anOr1=(aPave1->Vertex()).Orientation();
    if (aVerOriMap.IsBound(aV1)) {
      // MSV: restore orientation of removed vertex
      TColStd_ListOfInteger& anOriList = aVerOriMap(aV1);
      if (!anOriList.IsEmpty()) {
        if (anOriList.First()) {
          TColStd_ListIteratorOfListOfInteger it(anOriList); it.Next();
          anOr1 = (TopAbs_Orientation) it.Value();
        }
        anOriList.RemoveFirst(); anOriList.RemoveFirst();
      }
    }

    aPVSit.Next();

    if (!aPVSit.More()) break;

    Handle(TopOpeBRepBuild_Pave) aPave2 = aPVSit.Value();
    TopoDS_Shape aV2= aPave2->Vertex();
    aV2.Orientation(TopAbs_REVERSED);
    aPar2    = aPave2->Parameter();
    anOr2=(aPave2->Vertex()).Orientation();
    if (aVerOriMap.IsBound(aV2)) {
      TColStd_ListOfInteger& anOriList = aVerOriMap(aV2);
      if (!anOriList.IsEmpty()) {
        if (!anOriList.First()) {
          TColStd_ListIteratorOfListOfInteger it(anOriList); it.Next();
          anOr2 = (TopAbs_Orientation) it.Value();
        }
      }
    }

    // MSV: avoid creation of an edge with invalid range
    if (aPar1 > aPar2) continue;

    Standard_Boolean HasSDV1 = myDataStructure->HasSameDomain(aV1);
    Standard_Boolean HasSDV2 = myDataStructure->HasSameDomain(aV2);
    if (HasSDV1) { // on prend le vertex reference de V
      Standard_Integer iref = myDataStructure->SameDomainReference(aV1);
      aV1 = myDataStructure->Shape(iref);
      aV1.Orientation(TopAbs_FORWARD);
    }

    if (HasSDV2) { // on prend le vertex reference de V
      Standard_Integer iref = myDataStructure->SameDomainReference(aV2);
      aV2 = myDataStructure->Shape(iref);
      aV2.Orientation(TopAbs_REVERSED);
    }

    // Make new edge from EdgeF
    TopoDS_Edge aNewEdge;
    myBuildTool.CopyEdge (EdgeF, aNewEdge);
    
    Standard_Boolean bitclosed = aV1.IsSame(aV2);
    aNewEdge.Closed(bitclosed);

    myBuildTool.AddEdgeVertex (aNewEdge, aV1);
    myBuildTool.Parameter     (aNewEdge, aV1, aPar1);
    
    myBuildTool.AddEdgeVertex (aNewEdge, aV2);
    myBuildTool.Parameter     (aNewEdge, aV2, aPar2);
    // State of piece
    
    
    TopAbs_State aState=TopAbs_IN;
 
    if (anOr1==TopAbs_FORWARD  && anOr2==TopAbs_REVERSED) aState=TopAbs_OUT;
    if (anOr1==TopAbs_FORWARD  && anOr2==TopAbs_INTERNAL) aState=TopAbs_OUT;
    if (anOr1==TopAbs_INTERNAL && anOr2==TopAbs_REVERSED) aState=TopAbs_OUT;
    ///* Added
    if (anOr1==TopAbs_INTERNAL && anOr2==TopAbs_INTERNAL) aState=TopAbs_OUT;
    //printf(" anOr1=%d, anOr2=%d\n", anOr1, anOr2);

    // set old orientation to new edge;
    aNewEdge.Orientation (anEdge.Orientation()); 
    aLNew.Append(aNewEdge);
    aDataMapOfShapeState.Bind(aNewEdge, aState);
  }
  //GEDBUMakeEdges(EdgeF,EDBU,aListOfShape);
}

static TopAbs_State ClassifyEdgeToSolidByOnePoint(const TopoDS_Edge& E,
						  TopOpeBRepTool_ShapeClassifier& SC)
{
  Standard_Real f2 = 0., l2 = 0., par = 0.;

  Handle(Geom_Curve) C3D = BRep_Tool::Curve(E, f2, l2);
  gp_Pnt aP3d;

  if(C3D.IsNull()) {
    //it means that we are in degenerated edge
    const TopoDS_Vertex& fv = TopExp::FirstVertex(E);
    if(fv.IsNull())
      return TopAbs_UNKNOWN;
    aP3d = BRep_Tool::Pnt(fv);
  }
  else {//usual case
    par = f2*PAR_T + (1 - PAR_T)*l2;
    C3D -> D0(par, aP3d);
  }
    
  SC.StateP3DReference(aP3d);

  return SC.State();
}
