]> OCCT Git - occt.git/commitdiff
0032922: Data Exchange, STEP - The torus is stored incorrectly in STEP format
authoratereshi <atereshi@opencascade.com>
Fri, 8 Apr 2022 11:16:01 +0000 (14:16 +0300)
committerafokin <afokin@opencascade.com>
Fri, 27 May 2022 15:14:03 +0000 (18:14 +0300)
Problem: the complete surface of the torus is not stored correctly in STEP format due to the fact that the edges are not properly ordered.
Change: added a mode for reordering edges in the wire with simultaneous use of 2d and 3d information (ShapeAnalysis_WireOrder). The new mode is used for torus-like surfaces before saving to STEP format.
 Result: Torus correctly stored.

src/ShapeAnalysis/ShapeAnalysis_Wire.cxx
src/ShapeAnalysis/ShapeAnalysis_Wire.hxx
src/ShapeAnalysis/ShapeAnalysis_WireOrder.cxx
src/ShapeAnalysis/ShapeAnalysis_WireOrder.hxx
src/ShapeFix/ShapeFix_Wire.cxx
src/ShapeFix/ShapeFix_Wire.hxx
src/TopoDSToStep/TopoDSToStep_MakeStepWire.cxx
tests/bugs/step/bug28256
tests/bugs/step/bug32922 [new file with mode: 0644]

index d7fc1edba239f4198cd948386197709247b6eaa7..71560d84c7578c0e3b17dcfd350ba513b572c1d5 100644 (file)
@@ -260,7 +260,7 @@ void ShapeAnalysis_Wire::SetSurface (const Handle(Geom_Surface)& surface,
                                                   const Standard_Boolean mode3d) 
 {
   ShapeAnalysis_WireOrder sawo;
-  CheckOrder (sawo, isClosed, mode3d);
+  CheckOrder (sawo, isClosed, mode3d, Standard_False);
   myStatusOrder = myStatus;
   return StatusOrder (ShapeExtend_DONE);
 }
@@ -550,54 +550,94 @@ void ShapeAnalysis_Wire::SetSurface (const Handle(Geom_Surface)& surface,
 //purpose  : 
 //=======================================================================
 
-Standard_Boolean ShapeAnalysis_Wire::CheckOrder(ShapeAnalysis_WireOrdersawo,
+Standard_Boolean ShapeAnalysis_Wire::CheckOrder(ShapeAnalysis_WireOrder &sawo,
                                                 const Standard_Boolean isClosed,
-                                                const Standard_Boolean mode3d) 
+                                                const Standard_Boolean theMode3D,
+                                                const Standard_Boolean theModeBoth)
 {
-  if ( ! mode3d && myFace.IsNull() ) {
-    myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2); 
+  if ((!theMode3D || theModeBoth) && myFace.IsNull())
+  {
+    myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
     return Standard_False;
   }
-  
   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
-  sawo.SetMode ( mode3d, ( mode3d ? myPrecision : ::Precision::PConfusion() ) );
-  Standard_Integer i, nb = myWire->NbEdges();
+  sawo.SetMode(theMode3D, 0.0, theModeBoth);
+  Standard_Integer nb = myWire->NbEdges();
   ShapeAnalysis_Edge EA;
-  for (i = 1; i <= nb; i ++) {
+  Standard_Boolean isAll2dEdgesOk = Standard_True;
+  for (Standard_Integer i = 1; i <= nb; i++)
+  {
     TopoDS_Edge E = myWire->Edge(i);
-    if ( mode3d ) {
-      TopoDS_Vertex V1 = EA.FirstVertex (E); 
-      TopoDS_Vertex V2 = EA.LastVertex  (E); 
+    gp_XYZ aP1XYZ, aP2XYZ;
+    gp_XY aP1XY, aP2XY;
+    if (theMode3D || theModeBoth)
+    {
+      TopoDS_Vertex V1 = EA.FirstVertex(E);
+      TopoDS_Vertex V2 = EA.LastVertex(E);
       if (V1.IsNull() || V2.IsNull())
       {
         myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
         return Standard_False;
       }
-      gp_Pnt p1 = BRep_Tool::Pnt (V1);
-      gp_Pnt p2 = BRep_Tool::Pnt (V2);
-      sawo.Add (p1.XYZ(),p2.XYZ());
+      else
+      {
+        aP1XYZ = BRep_Tool::Pnt(V1).XYZ();
+        aP2XYZ = BRep_Tool::Pnt(V2).XYZ();
+      }
     }
-    else {
-      Standard_Real f,l;
+    if (!theMode3D || theModeBoth)
+    {
+      Standard_Real f, l;
       Handle(Geom2d_Curve) c2d;
-      TopoDS_Shape tmpF = myFace.Oriented(TopAbs_FORWARD);
-      if ( ! EA.PCurve(E,TopoDS::Face(tmpF),c2d,f,l) ) {
-        myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
-        return Standard_False;
+      TopoDS_Shape tmpF = myFace.Oriented (TopAbs_FORWARD);
+      if (!EA.PCurve(E, TopoDS::Face (tmpF), c2d, f, l))
+      {
+        // if mode is 2d, then we can nothing to do, else we can switch to 3d mode
+        if (!theMode3D && !theModeBoth)
+        {
+          myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
+          return Standard_False;
+        }
+        else
+        {
+          isAll2dEdgesOk = Standard_False;
+        }
+      }
+      else
+      {
+        aP1XY = c2d->Value(f).XY();
+        aP2XY = c2d->Value(l).XY();
       }
-      sawo.Add(c2d->Value(f).XY(),c2d->Value(l).XY());
+    }
+    if (theMode3D && !theModeBoth)
+    {
+      sawo.Add (aP1XYZ, aP2XYZ);
+    }
+    else if (!theMode3D && !theModeBoth)
+    {
+      sawo.Add (aP1XY, aP2XY);
+    }
+    else
+    {
+      sawo.Add (aP1XYZ, aP2XYZ, aP1XY, aP2XY);
     }
   }
-  sawo.Perform(isClosed);
+  // need to switch to 3d mode
+  if (theModeBoth && !isAll2dEdgesOk)
+  {
+    sawo.SetMode (Standard_True, 0.0, Standard_False);
+  }
+  sawo.Perform (isClosed);
   Standard_Integer stat = sawo.Status();
-  switch (stat) {
+  switch (stat)
+  {
   case   0: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);    break;
   case   1: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1); break;
-  case   2: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE2); break;
+  case   2: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE2); break; // this value is not returned
   case  -1: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE3); break;
-  case  -2: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE4); break;
-  case   3: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE5); break;//only shifted
-  case -10: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1); break;
+  case  -2: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE4); break; // this value is not returned
+  case   3: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE5); break; // only shifted
+  case -10: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1); break; // this value is not returned
   }
   return LastCheckStatus (ShapeExtend_DONE);
 }
index 3bce04c331b4f129593bf4c8e5290104532dd1a9..c2bc90c7f144aebc11518cbcfd5fc0deea50e351 100644 (file)
@@ -232,7 +232,8 @@ public:
   //! Analyzes the order of the edges in the wire,
   //! uses class WireOrder for that purpose.
   //! Flag <isClosed> defines if the wire is closed or not
-  //! Flag <mode3d> defines which mode is used (3d or 2d)
+  //! Flag <theMode3D> defines 3D or 2d mode.
+  //! Flag <theModeBoth> defines miscible mode and the flag <theMode3D> is ignored.
   //! Returns False if wire is already ordered (tail-to-head),
   //! True otherwise.
   //! Use returned WireOrder object for deeper analysis.
@@ -243,7 +244,10 @@ public:
   //! DONE3: not the same edges orientation (some need to be reversed)
   //! DONE4: as DONE3 and gaps more than myPrecision
   //! FAIL : algorithm failed (could not detect order)
-  Standard_EXPORT Standard_Boolean CheckOrder (ShapeAnalysis_WireOrder& sawo, const Standard_Boolean isClosed = Standard_True, const Standard_Boolean mode3d = Standard_True);
+  Standard_EXPORT Standard_Boolean CheckOrder(ShapeAnalysis_WireOrder &sawo,
+                                              Standard_Boolean isClosed = Standard_True,
+                                              Standard_Boolean theMode3D = Standard_True,
+                                              Standard_Boolean theModeBoth = Standard_False);
   
   //! Checks connected edges (num-th and preceding).
   //! Tests with starting preci from <SBWD> or  with <prec> if
index 0d6f9e03b4c8231e28aa7c26378ba3f095240332..0b8b34c4f0abd7914c550956105055e120702ded 100644 (file)
 #include <gp_XYZ.hxx>
 #include <Precision.hxx>
 #include <ShapeAnalysis_WireOrder.hxx>
-#include <Standard_TypeMismatch.hxx>
 #include <TColgp_Array1OfXYZ.hxx>
+#include <TColgp_Array1OfXY.hxx>
 #include <TColStd_Array1OfBoolean.hxx>
-#include <TColStd_Array1OfInteger.hxx>
 #include <TColStd_HSequenceOfInteger.hxx>
 #include <TColStd_SequenceOfInteger.hxx>
 #include <TColStd_SequenceOfTransient.hxx>
@@ -34,7 +33,7 @@
 //purpose  : 
 //=======================================================================
 ShapeAnalysis_WireOrder::ShapeAnalysis_WireOrder()
-  : myKeepLoops(Standard_False) , myGap (0.) , myStat (0)  , myMode (Standard_True) 
+        : myGap (0.0), myStat (0), myKeepLoops (Standard_False), myMode (Mode3D)
 {
   myTol = Precision::Confusion();
   Clear();
@@ -45,10 +44,26 @@ ShapeAnalysis_WireOrder::ShapeAnalysis_WireOrder()
 //purpose  : 
 //=======================================================================
 
-ShapeAnalysis_WireOrder::ShapeAnalysis_WireOrder(const Standard_Boolean mode3d,
-                                                 const Standard_Real tol)
-  : myKeepLoops(Standard_False), myTol (tol), myGap (0.), myStat (0), myMode (mode3d)
+ShapeAnalysis_WireOrder::ShapeAnalysis_WireOrder (const Standard_Boolean theMode3D,
+                                                  const Standard_Real theTolerance,
+                                                  const Standard_Boolean theModeBoth)
+        : myTol (theTolerance), myGap (0.0), myStat (0), myKeepLoops (Standard_False)
 {
+  if (theModeBoth)
+  {
+    myMode = ModeBoth;
+  }
+  else
+  {
+    if (theMode3D)
+    {
+      myMode = Mode3D;
+    }
+    else
+    {
+      myMode = Mode2D;
+    }
+  }
   Clear();
 }
 
@@ -57,12 +72,36 @@ ShapeAnalysis_WireOrder::ShapeAnalysis_WireOrder(const Standard_Boolean mode3d,
 //purpose  : 
 //=======================================================================
 
-void ShapeAnalysis_WireOrder::SetMode(const Standard_Boolean mode3d,const Standard_Real tol) 
+void ShapeAnalysis_WireOrder::SetMode (const Standard_Boolean theMode3D,
+                                       const Standard_Real theTolerance,
+                                       const Standard_Boolean theModeBoth)
 {
-  if (mode3d != myMode) Clear();
-  myOrd.Nullify();  myStat = 0; myGap = 0.;
-  myMode = mode3d;
-  myTol = (tol > 0.)? tol : 1.e-08; //szv#4:S4163:12Mar99 optimized
+  ModeType aNewMode;
+
+  if (theModeBoth)
+  {
+    aNewMode = ModeBoth;
+  }
+  else
+  {
+    if (theMode3D)
+    {
+      aNewMode = Mode3D;
+    }
+    else
+    {
+      aNewMode = Mode2D;
+    }
+  }
+  if (myMode != aNewMode)
+  {
+    Clear();
+  }
+  myMode = aNewMode;
+  myOrd.Nullify();
+  myStat = 0;
+  myGap = 0.0;
+  myTol = (theTolerance > 0.0) ? theTolerance : 1.e-08;
 }
 
 //=======================================================================
@@ -80,11 +119,12 @@ Standard_Real ShapeAnalysis_WireOrder::Tolerance() const
 //purpose  : 
 //=======================================================================
 
-void ShapeAnalysis_WireOrder::Clear() 
+void ShapeAnalysis_WireOrder::Clear()
 {
   myXYZ = new TColgp_HSequenceOfXYZ();
+  myXY = new TColgp_HSequenceOfXY();
   myStat = 0;
-  myGap = 0.;
+  myGap = 0.0;
 }
 
 //=======================================================================
@@ -92,13 +132,12 @@ void ShapeAnalysis_WireOrder::Clear()
 //purpose  : 
 //=======================================================================
 
-void ShapeAnalysis_WireOrder::Add(const gp_XYZ& start3d,const gp_XYZ& end3d) 
+void ShapeAnalysis_WireOrder::Add (const gp_XYZ& theStart3d, const gp_XYZ& theEnd3d)
 {
-  //szv#4:S4163:12Mar99 waste raise
-  //if (!myMode)
-    //throw Standard_TypeMismatch("ShapeAnalysis_WireOrder : AddXYZ");
-  if (myMode) {
-    myXYZ->Append (start3d);  myXYZ->Append (end3d);
+  if (myMode == Mode3D)
+  {
+    myXYZ->Append (theStart3d);
+    myXYZ->Append (theEnd3d);
   }
 }
 
@@ -107,20 +146,38 @@ void ShapeAnalysis_WireOrder::Add(const gp_XYZ& start3d,const gp_XYZ& end3d)
 //purpose  : 
 //=======================================================================
 
-void ShapeAnalysis_WireOrder::Add(const gp_XY& start2d,const gp_XY& end2d) 
+void ShapeAnalysis_WireOrder::Add (const gp_XY& theStart2d, const gp_XY& theEnd2d)
 {
-  //szv#4:S4163:12Mar99 waste raise
-  //if ( myMode)
-    //throw Standard_TypeMismatch("ShapeAnalysis_WireOrder : AddXY");
-  if (!myMode) {
+  if (myMode == Mode2D)
+  {
     gp_XYZ val;
-    val.SetCoord (start2d.X(),start2d.Y(),0.);
+    val.SetCoord (theStart2d.X(), theStart2d.Y(), 0.0);
     myXYZ->Append (val);
-    val.SetCoord (end2d.X(),end2d.Y(),0.);
+    val.SetCoord (theEnd2d.X(), theEnd2d.Y(), 0.0);
     myXYZ->Append (val);
   }
 }
 
+//=======================================================================
+//function : Add
+//purpose  :
+//=======================================================================
+
+void ShapeAnalysis_WireOrder::Add (const gp_XYZ& theStart3d,
+                                   const gp_XYZ& theEnd3d,
+                                   const gp_XY& theStart2d,
+                                   const gp_XY& theEnd2d)
+{
+  if (myMode == ModeBoth)
+  {
+    myXYZ->Append (theStart3d);
+    myXYZ->Append (theEnd3d);
+
+    myXY->Append (theStart2d);
+    myXY->Append (theEnd2d);
+  }
+}
+
 //=======================================================================
 //function : NbEdges
 //purpose  : 
@@ -166,234 +223,480 @@ Standard_Boolean& ShapeAnalysis_WireOrder::KeepLoopsMode()
 
 //=======================================================================
 //function : Perform
-//purpose  : 
+//purpose  : Make wire order analysis and propose the better order of the edges
+//           taking into account the gaps between edges.
 //=======================================================================
 
-static Standard_Boolean IsBetter(const Standard_Integer first,
-                                const Standard_Integer second)
-{
-  //rln 23.03.99 bm4_al_eye.stp, entity 5281
-  //Order in the file is better even if another order has the same distance
-  //Lexicograhical order of preference: 0 > 2 > 1 > 3
-  if (first == 0 &&  second  > 0                ) return Standard_True;
-  if (first == 2 && (second == 1 || second == 3)) return Standard_True;
-  if (first == 1 &&  second == 3                ) return Standard_True;
-  return Standard_False;
-}
-
-void ShapeAnalysis_WireOrder::Perform(const Standard_Boolean /*closed*/) 
+void ShapeAnalysis_WireOrder::Perform (const Standard_Boolean /*closed*/)
 {
   myStat = 0;
-  Standard_Integer i, nb = NbEdges();
-  if(nb == 0)
-    return; // no edges loaded, nothing to do -- return with status OK
-  myOrd = new TColStd_HArray1OfInteger(1,nb);
-  myOrd->Init(0);
-
-  Handle(TColStd_HSequenceOfInteger) seq = new TColStd_HSequenceOfInteger;
-  TColStd_SequenceOfTransient loops;
-  
-  TColgp_Array1OfXYZ debs(0,nb);
-  TColgp_Array1OfXYZ fins(0,nb);
-  
-  TColStd_Array1OfBoolean idone (1, nb);
-  idone.Init (Standard_False);
-  
-//   Calcul des precedents-suivants
-  for (i = 1; i <= nb; i ++) {
-    debs(i) = myXYZ->Value(2*i-1);
-    fins(i) = myXYZ->Value(2*i);
+  Standard_Integer aNbEdges = NbEdges();
+  // no edges loaded, nothing to do -- return with status OK
+  if (aNbEdges == 0)
+  {
+    return;
+  }
+  myOrd = new TColStd_HArray1OfInteger (1, aNbEdges);
+  myOrd->Init (0);
+
+  // sequence of the edge nums in the right order
+  Handle(TColStd_HSequenceOfInteger) anEdgeSeq = new TColStd_HSequenceOfInteger;
+  NCollection_Sequence<Handle(TColStd_HSequenceOfInteger) > aLoops;
+
+  // the beginnings and ends of the edges
+  TColgp_Array1OfXYZ aBegins3D (1, aNbEdges);
+  TColgp_Array1OfXYZ anEnds3D (1, aNbEdges);
+  TColgp_Array1OfXY aBegins2D (1, aNbEdges);
+  TColgp_Array1OfXY anEnds2D (1, aNbEdges);
+  for (Standard_Integer i = 1; i <= aNbEdges; i++)
+  {
+    aBegins3D (i) = myXYZ->Value (2 * i - 1);
+    anEnds3D (i) = myXYZ->Value (2 * i);
+    if (myMode == ModeBoth)
+    {
+      aBegins2D (i) = myXY->Value (2 * i - 1);
+      anEnds2D (i) = myXY->Value (2 * i);
+    }
   }
+  // the flags that the edges was considered
+  TColStd_Array1OfBoolean isEdgeUsed (1, aNbEdges);
+  isEdgeUsed.Init (Standard_False);
+
+  Standard_Real aTol2 = Precision::SquareConfusion();
+  Standard_Real aTolP2 = Precision::SquarePConfusion();
+
+  // take the first edge to the constructed chain
+  isEdgeUsed (1) = Standard_True;
+  gp_Pnt aFirstPnt3D = aBegins3D (1);
+  gp_Pnt aLastPnt3D = anEnds3D (1);
+  gp_Pnt2d aFirstPnt2D;
+  gp_Pnt2d aLastPnt2D;
+  if (myMode == ModeBoth)
+  {
+    aFirstPnt2D = aBegins2D (1);
+    aLastPnt2D = anEnds2D (1);
+  }
+  anEdgeSeq->Append (1);
+
+  // cycle until all edges are considered
+  for (;;)
+  {
+    // joint type
+    // 0 - the start of the best edge to the end of constructed sequence (nothing to do)
+    // 1 - the end of the best edge to the start of constructed sequence (need move the edge)
+    // 2 - the end of the best edge to the end of constructed sequence (need to reverse)
+    // 3 - the start of the best edge to the start of constructed sequence (need to reverse and move the edge)
+    Standard_Integer aBestJointType = 3;
+    // the best minimum distance between constructed sequence and the best edge
+    Standard_Real aBestMin3D = RealLast();
+    // number of the best edge
+    Standard_Integer aBestEdgeNum = 0;
+    // the best edge was found
+    Standard_Boolean isFound = Standard_False;
+    Standard_Boolean isConnected = Standard_False;
+    // loop to find the best edge among all the remaining
+    for (Standard_Integer i = 1; i <= aNbEdges; i++)
+    {
+      if (isEdgeUsed (i))
+      {
+        continue;
+      }
 
-  Standard_Real tol2 = Precision::SquareConfusion();
-  idone(1) = Standard_True;
-  gp_Pnt wireFirst = debs(1);
-  gp_Pnt wireLast  = fins(1);
-  seq->Append(1);
-  Standard_Boolean done = Standard_False;
-  
-  //pdn 11.03.99 S4135 constructing closed loops of edges
-  while(!done) {
-    Standard_Integer resultType = 3;
-    Standard_Real distmin = RealLast();
-    Standard_Integer ledge = 0;
-    Standard_Boolean found = Standard_False;
-    Standard_Real closeDist = wireFirst.SquareDistance(wireLast);
-    
-    for(Standard_Integer iedge = 1; (iedge <= nb) && (distmin||resultType||(resultType!=2)); iedge++)
-      if(!idone(iedge)) {
-       Standard_Real tailhead = wireLast.SquareDistance(debs(iedge));
-       Standard_Real tailtail = wireLast.SquareDistance(fins(iedge));
-       Standard_Real headtail = wireFirst.SquareDistance(fins(iedge));
-       Standard_Real headhead = wireFirst.SquareDistance(debs(iedge));
-       Standard_Real dm1 = tailhead, dm2 = headtail;
-       Standard_Integer res1 = 0, res2 = 2;
-
-       if (tailhead > tailtail) {res1 = 1; dm1 = tailtail;}
-       if (headtail > headhead) {res2 = 3; dm2 = headhead;}
-       Standard_Integer result =0;
-       Standard_Real myMin3d = Min (dm1, dm2);
-       if(fabs(dm1 - dm2) < tol2 ) {
-          Standard_Boolean isB = IsBetter(res1,res2);
-         result = (isB ? res1 : res2);
+      // find minimum distance and joint type for 3D and 2D (if necessary) modes
+      Standard_Integer aCurJointType;
+      Standard_Real aCurMin;
+      // distance for four possible cases
+      Standard_Real aSeqTailEdgeHead = aLastPnt3D.SquareDistance (aBegins3D (i));
+      Standard_Real aSeqTailEdgeTail = aLastPnt3D.SquareDistance (anEnds3D (i));
+      Standard_Real aSeqHeadEdgeTail = aFirstPnt3D.SquareDistance (anEnds3D (i));
+      Standard_Real aSeqHeadEdgeHead = aFirstPnt3D.SquareDistance (aBegins3D (i));
+      // the best distances for joints with head and tail of sequence
+      Standard_Real aMinDistToTail, aMinDistToHead;
+      Standard_Integer aTailJoinType, aHeadJointType;
+      if (aSeqTailEdgeHead <= aSeqTailEdgeTail)
+      {
+        aTailJoinType = 0;
+        aMinDistToTail = aSeqTailEdgeHead;
+      }
+      else
+      {
+        aTailJoinType = 2;
+        aMinDistToTail = aSeqTailEdgeTail;
+      }
+      if (aSeqHeadEdgeTail <= aSeqHeadEdgeHead)
+      {
+        aHeadJointType = 1;
+        aMinDistToHead = aSeqHeadEdgeTail;
+      }
+      else
+      {
+        aHeadJointType = 3;
+        aMinDistToHead = aSeqHeadEdgeHead;
+      }
+      // comparing the head and the tail cases
+      // if distances are close enough then we use rule for joint type: 0 < 1 < 2 < 3
+      if (fabs (aMinDistToTail - aMinDistToHead) < aTol2)
+      {
+        if (aTailJoinType < aHeadJointType)
+        {
+          aCurJointType = aTailJoinType;
+          aCurMin = aMinDistToTail;
+        }
+        else
+        {
+          aCurJointType = aHeadJointType;
+          aCurMin = aMinDistToHead;
+        }
+      }
+      else
+      {
+        if (aMinDistToTail <= aMinDistToHead)
+        {
+          aCurJointType = aTailJoinType;
+          aCurMin = aMinDistToTail;
+        }
+        else
+        {
+          aCurJointType = aHeadJointType;
+          aCurMin = aMinDistToHead;
+        }
+      }
+      // update for the best values
+      if (myMode == ModeBoth)
+      {
+        // distances in 2D
+        Standard_Integer aJointMask3D = 0, aJointMask2D = 0;
+        if (aSeqTailEdgeHead < aTol2)
+        {
+          aJointMask3D |= (1 << 0);
+        }
+        if (aSeqTailEdgeTail < aTol2)
+        {
+          aJointMask3D |= (1 << 2);
+        }
+        if (aSeqHeadEdgeTail < aTol2)
+        {
+          aJointMask3D |= (1 << 1);
+        }
+        if (aSeqHeadEdgeHead < aTol2)
+        {
+          aJointMask3D |= (1 << 3);
+        }
+        Standard_Real aSeqTailEdgeHead2D = aLastPnt2D.SquareDistance (aBegins2D (i));
+        Standard_Real aSeqTailEdgeTail2D = aLastPnt2D.SquareDistance (anEnds2D (i));
+        Standard_Real aSeqHeadEdgeTail2D = aFirstPnt2D.SquareDistance (anEnds2D (i));
+        Standard_Real aSeqHeadEdgeHead2D = aFirstPnt2D.SquareDistance (aBegins2D (i));
+        if (aSeqTailEdgeHead2D < aTolP2)
+        {
+          aJointMask2D |= (1 << 0);
+        }
+        if (aSeqTailEdgeTail2D < aTolP2)
+        {
+          aJointMask2D |= (1 << 2);
+        }
+        if (aSeqHeadEdgeTail2D < aTolP2)
+        {
+          aJointMask2D |= (1 << 1);
+        }
+        if (aSeqHeadEdgeHead2D < aTolP2)
+        {
+          aJointMask2D |= (1 << 3);
+        }
+        // new approche for detecting best edge connection, for all other cases used old 3D algorithm
+        Standard_Integer aFullMask = aJointMask3D & aJointMask2D;
+        if (aFullMask != 0)
+        {
+          // find the best current joint type
+          aCurJointType = 3;
+          for (Standard_Integer j = 0; j < 4; j++)
+          {
+            if (aFullMask & (1 << j))
+            {
+              aCurJointType = j;
+              break;
+            }
+          }
+          if (!isConnected || aCurJointType < aBestJointType)
+          {
+            isFound = Standard_True;
+            isConnected = Standard_True;
+            switch (aCurJointType)
+            {
+              case 0:
+                aBestMin3D = aSeqTailEdgeHead;
+                break;
+              case 1:
+                aBestMin3D = aSeqHeadEdgeTail;
+                break;
+              case 2:
+                aBestMin3D = aSeqTailEdgeTail;
+                break;
+              case 3:
+                aBestMin3D = aSeqHeadEdgeHead;
+                break;
+            }
+            aBestJointType = aCurJointType;
+            aBestEdgeNum = i;
+          }
+        }
+        // if there is still no connection, continue to use ald 3D algorithm
+        if (isConnected)
+        {
+          continue;
         }
-       else 
-         result = ((dm1 > dm2) ? res2 : res1); // 0 > 2 > 1 > 3
-       
-       if (distmin > tol2 || IsBetter(result,resultType))
-         if (myMin3d < distmin || ((myMin3d == distmin || myMin3d < tol2) && IsBetter(result,resultType))) {
-           found = Standard_True;
-           distmin = myMin3d;
-           ledge = iedge;
-           resultType = result;
-         }
       }
-    if(found) {
-      if (distmin == 0 || distmin < closeDist) {
-       switch(resultType){
-       case 0: seq->Append(ledge); wireLast = fins(ledge); break;
-       case 1: seq->Append(-ledge); wireLast = debs(ledge); break;
-       case 2: seq->Prepend(ledge); wireFirst = debs(ledge); break;
-       case 3: seq->Prepend(-ledge); wireFirst = fins(ledge); break;
-       }
-      } else {
-       //pdn 11.03.99 S4135 closing loop and creating new one
-       loops.Append(seq);
-       seq = new TColStd_HSequenceOfInteger;
-       wireFirst = debs(ledge);
-       wireLast  = fins(ledge);
-       seq->Append(ledge);
+      // if the best distance is still not reached (aBestMin3D > aTol2) or we found a better joint type
+      if (aBestMin3D > aTol2 || aCurJointType < aBestJointType)
+      {
+        // make a decision that this edge is good enough:
+        // - it gets the best distance but there is fabs(aCurMin3d - aBestMin3d) < aTol2 && (aCurJointType < aBestJointType) ?
+        // - it gets the best joint in some cases
+        if (aCurMin < aBestMin3D || ((aCurMin == aBestMin3D || aCurMin < aTol2) && (aCurJointType < aBestJointType)))
+        {
+          isFound = Standard_True;
+          aBestMin3D = aCurMin;
+          aBestJointType = aCurJointType;
+          aBestEdgeNum = i;
+        }
+      }
+    }
+
+    // check that we found edge for connecting
+    if (isFound)
+    {
+      // distance between first and last point in sequence
+      Standard_Real aCloseDist = aFirstPnt3D.SquareDistance (aLastPnt3D);
+      // if it's better to insert the edge than to close the loop, just insert the edge according to joint type
+      if (aBestMin3D <= RealSmall() || aBestMin3D < aCloseDist)
+      {
+        switch (aBestJointType)
+        {
+          case 0:
+            anEdgeSeq->Append (aBestEdgeNum);
+            aLastPnt3D = anEnds3D (aBestEdgeNum);
+            break;
+          case 1:
+            anEdgeSeq->Prepend (aBestEdgeNum);
+            aFirstPnt3D = aBegins3D (aBestEdgeNum);
+            break;
+          case 2:
+            anEdgeSeq->Append (-aBestEdgeNum);
+            aLastPnt3D = aBegins3D (aBestEdgeNum);
+            break;
+          case 3:
+            anEdgeSeq->Prepend (-aBestEdgeNum);
+            aFirstPnt3D = anEnds3D (aBestEdgeNum);
+            break;
+        }
+        if (myMode == ModeBoth)
+        {
+          switch (aBestJointType)
+          {
+            case 0:
+              aLastPnt2D = anEnds2D (aBestEdgeNum);
+              break;
+            case 1:
+              aFirstPnt2D = aBegins2D (aBestEdgeNum);
+              break;
+            case 2:
+              aLastPnt2D = aBegins2D (aBestEdgeNum);
+              break;
+            case 3:
+              aFirstPnt2D = anEnds2D (aBestEdgeNum);
+              break;
+          }
+        }
       }
-      idone(ledge) = Standard_True;
-    } else {
-      ledge = -1;
-      for (i = 1 ; i <= nb && ledge == -1; i++)
-       ledge = idone(i) ? ledge : i;
-      if (ledge == -1) 
-       done = 1;
-      else {
-       wireFirst = debs(ledge);
-       wireLast  = fins(ledge);
-       seq->Append(ledge);
-       idone(ledge) = Standard_True;
+        // closing loop and creating new one
+      else
+      {
+        aLoops.Append (anEdgeSeq);
+        anEdgeSeq = new TColStd_HSequenceOfInteger;
+        aFirstPnt3D = aBegins3D (aBestEdgeNum);
+        aLastPnt3D = anEnds3D (aBestEdgeNum);
+        if (myMode == ModeBoth)
+        {
+          aFirstPnt2D = aBegins2D (aBestEdgeNum);
+          aLastPnt2D = anEnds2D (aBestEdgeNum);
+        }
+        anEdgeSeq->Append (aBestEdgeNum);
       }
+      // mark the edge as used
+      isEdgeUsed (aBestEdgeNum) = Standard_True;
+    }
+    else
+    {
+      // the only condition under which we can't find an edge is when all edges are done
+      break;
     }
   }
-  loops.Append(seq);
-
-  Handle(TColStd_HSequenceOfInteger) mainSeq;
-  if (myKeepLoops) {
-    
-    //pdn Keeping the loops, adding one after another.
-    mainSeq = new TColStd_HSequenceOfInteger;
-    for (Standard_Integer ii = 1; ii <= loops.Length(); ii++) {
-      Handle(TColStd_HSequenceOfInteger) subLoop = 
-        Handle(TColStd_HSequenceOfInteger)::DownCast(loops(ii));
-      for (Standard_Integer j = 1; j<= subLoop->Length(); j++)
-        mainSeq->Append(subLoop->Value(j));
+  // append the last loop
+  aLoops.Append (anEdgeSeq);
+
+  // handling with constructed loops
+  Handle(TColStd_HSequenceOfInteger) aMainLoop;
+  if (myKeepLoops)
+  {
+    // keeping the loops, adding one after another.
+    aMainLoop = new TColStd_HSequenceOfInteger;
+    for (Standard_Integer i = 1; i <= aLoops.Length(); i++)
+    {
+      const Handle(TColStd_HSequenceOfInteger)& aCurLoop = aLoops (i);
+      aMainLoop->Append (aCurLoop);
     }
   }
-  else {
-    //pdn 11.03.99 S4135 connecting loops.
-    mainSeq = Handle(TColStd_HSequenceOfInteger)::DownCast(loops.First());
-    loops.Remove(1);
-    while(loops.Length()) {
-      Standard_Real minLoopDist = RealLast();
-      Standard_Integer loopNum=0;
-      Standard_Integer loopShift=0;
-      Standard_Boolean loopDirect=0;
-      Standard_Integer numInLoop=0;
-      for(i = 1; i <= loops.Length(); i++) {
-        Handle(TColStd_HSequenceOfInteger) loop = Handle(TColStd_HSequenceOfInteger)::DownCast(loops.Value(i));
-        Standard_Integer num = loop->Length();
-        Standard_Integer LocShift=0;
-        Standard_Integer LocNumInLoop=0;
-        Standard_Boolean LocDirect = Standard_False;
-        Standard_Real minLocDist = RealLast();
-        for(Standard_Integer ibegin = 1; ibegin <= loop->Length(); ibegin++) {
-          Standard_Integer iend = (ibegin==1 ? num : ibegin -1);
-          gp_Pnt loopFirst = (loop->Value(ibegin) > 0 ? debs(loop->Value(ibegin)) : fins(-loop->Value(ibegin)));
-          gp_Pnt loopLast = (loop->Value(iend) > 0 ? fins(loop->Value(iend)) : debs(-loop->Value(iend)));
-          Standard_Real distmin = RealLast();
-          Standard_Integer lloop=0;
-          Standard_Boolean direct = Standard_False;
-          for(Standard_Integer j = 1; (j <= mainSeq->Length())&& distmin; j++) {
-            Standard_Integer k = (j == mainSeq->Length()? 1 : j+1);
-            gp_Pnt first = (mainSeq->Value(j) > 0 ? fins(mainSeq->Value(j)) : debs(-mainSeq->Value(j)));
-            gp_Pnt last  = (mainSeq->Value(k) > 0 ? debs(mainSeq->Value(k)) : fins(-mainSeq->Value(k)));
-            Standard_Real dirDist = loopFirst.SquareDistance(first)+loopLast.SquareDistance(last);
-            Standard_Real revDist = loopFirst.SquareDistance(last)+loopLast.SquareDistance(first);
-            Standard_Real minDist;
-            if((dirDist<tol2)||(dirDist < 2.*revDist)) {
-              minDist = dirDist;
-              revDist = dirDist;
+  else
+  {
+    // connecting loops
+    aMainLoop = aLoops.First();
+    aLoops.Remove (1);
+    while (aLoops.Length())
+    {
+      // iterate over all loops to find the closest one
+      Standard_Real aMinDist1 = RealLast();
+      Standard_Integer aLoopNum1 = 0;
+      Standard_Integer aCurLoopIt1 = 0;
+      Standard_Boolean aDirect1 = Standard_False;
+      Standard_Integer aMainLoopIt1 = 0;
+      for (Standard_Integer aLoopIt = 1; aLoopIt <= aLoops.Length(); aLoopIt++)
+      {
+        const Handle(TColStd_HSequenceOfInteger)& aCurLoop = aLoops.Value (aLoopIt);
+        // iterate over all gaps between edges in current loop
+        Standard_Integer aCurLoopIt2 = 0;
+        Standard_Integer aMainLoopIt2 = 0;
+        Standard_Boolean aDirect2 = Standard_False;
+        Standard_Real aMinDist2 = RealLast();
+        Standard_Integer aCurLoopLength = aCurLoop->Length();
+        for (Standard_Integer aCurEdgeIt = 1; aCurEdgeIt <= aCurLoopLength; aCurEdgeIt++)
+        {
+          // get the distance between the current edge and the previous edge taking into account the edge's orientation
+          Standard_Integer aPrevEdgeIt = aCurEdgeIt == 1 ? aCurLoopLength : aCurEdgeIt - 1;
+          Standard_Integer aCurEdgeIdx = aCurLoop->Value (aCurEdgeIt);
+          Standard_Integer aPrevEdgeIdx = aCurLoop->Value (aPrevEdgeIt);
+          gp_Pnt aCurLoopFirst = aCurEdgeIdx > 0 ? aBegins3D (aCurEdgeIdx) : anEnds3D (-aCurEdgeIdx);
+          gp_Pnt aCurLoopLast = aPrevEdgeIdx > 0 ? anEnds3D (aPrevEdgeIdx) : aBegins3D (-aPrevEdgeIdx);
+          // iterate over all gaps between edges in main loop
+          Standard_Real aMinDist3 = RealLast();
+          Standard_Integer aMainLoopIt3 = 0;
+          Standard_Boolean aDirect3 = Standard_False;
+          Standard_Integer aMainLoopLength = aMainLoop->Length();
+          for (Standard_Integer aCurEdgeIt2 = 1; (aCurEdgeIt2 <= aMainLoopLength) && aMinDist3 != 0.0; aCurEdgeIt2++)
+          {
+            // get the distance between the current edge and the next edge taking into account the edge's orientation
+            Standard_Integer aNextEdgeIt2 = aCurEdgeIt2 == aMainLoopLength ? 1 : aCurEdgeIt2 + 1;
+            Standard_Integer aCurEdgeIdx2 = aMainLoop->Value (aCurEdgeIt2);
+            Standard_Integer aNextEdgeIdx2 = aMainLoop->Value (aNextEdgeIt2);
+            gp_Pnt aMainLoopFirst = (aCurEdgeIdx2 > 0 ? anEnds3D (aCurEdgeIdx2) : aBegins3D (-aCurEdgeIdx2));
+            gp_Pnt aMainLoopLast = (aNextEdgeIdx2 > 0 ? aBegins3D (aNextEdgeIdx2) : anEnds3D (-aNextEdgeIdx2));
+            // getting the sum of square distances if we try to sew the current loop with the main loop in current positions
+            Standard_Real aDirectDist =
+                    aCurLoopFirst.SquareDistance (aMainLoopFirst) + aCurLoopLast.SquareDistance (aMainLoopLast);
+            Standard_Real aReverseDist =
+                    aCurLoopFirst.SquareDistance (aMainLoopLast) + aCurLoopLast.SquareDistance (aMainLoopFirst);
+            // take the best result
+            Standard_Real aJoinDist;
+            if ((aDirectDist < aTol2) || (aDirectDist < 2.0 * aReverseDist))
+            {
+              aJoinDist = aDirectDist;
+              aReverseDist = aDirectDist;
+            }
+            else
+            {
+              aJoinDist = aReverseDist;
             }
-            else 
-              minDist = revDist;
-            if(minDist < distmin && Abs(distmin - minDist) > tol2) {
-              distmin = minDist;
-              direct = (dirDist <= revDist);
-              lloop = j;
+            // check if we found a better distance
+            if (aJoinDist < aMinDist3 && Abs (aMinDist3 - aJoinDist) > aTol2)
+            {
+              aMinDist3 = aJoinDist;
+              aDirect3 = (aDirectDist <= aReverseDist);
+              aMainLoopIt3 = aCurEdgeIt2;
             }
           }
-          if(distmin < minLocDist && Abs(minLocDist - distmin) > tol2) {
-            minLocDist = distmin;
-            LocDirect = direct;
-            LocNumInLoop = lloop;
-            LocShift = ibegin;
+          // check if we found a better distance
+          if (aMinDist3 < aMinDist2 && Abs (aMinDist2 - aMinDist3) > aTol2)
+          {
+            aMinDist2 = aMinDist3;
+            aDirect2 = aDirect3;
+            aMainLoopIt2 = aMainLoopIt3;
+            aCurLoopIt2 = aCurEdgeIt;
           }
-         
         }
-        if(minLocDist < minLoopDist && Abs(minLoopDist - minLocDist) > tol2) {
-          minLoopDist = minLocDist;
-          loopNum = i;
-          loopDirect = LocDirect;
-          numInLoop = LocNumInLoop;
-          loopShift = LocShift;
+        // check if we found a better distance
+        if (aMinDist2 < aMinDist1 && Abs (aMinDist1 - aMinDist2) > aTol2)
+        {
+          aMinDist1 = aMinDist2;
+          aLoopNum1 = aLoopIt;
+          aDirect1 = aDirect2;
+          aMainLoopIt1 = aMainLoopIt2;
+          aCurLoopIt1 = aCurLoopIt2;
         }
       }
-      
-      Handle(TColStd_HSequenceOfInteger) loop = Handle(TColStd_HSequenceOfInteger)::DownCast(loops.Value(loopNum));
-      Standard_Integer factor = (loopDirect ? 1: -1);
-      // skl : in the next block for{} I change "i" to "ii"
-      for(Standard_Integer ii = 1; ii <= loop->Length(); ii++) {
-        Standard_Integer num = (ii+loopShift-1>loop->Length() ? ii+loopShift-1-loop->Length() : ii+loopShift-1);
-        mainSeq->InsertAfter(numInLoop+ii-1,loop->Value(num)*factor);
+      // insert the found loop into main loop
+      Handle(TColStd_HSequenceOfInteger) aLoop = aLoops.Value (aLoopNum1);
+      Standard_Integer aFactor = (aDirect1 ? 1 : -1);
+      for (Standard_Integer i = 0; i < aLoop->Length(); i++)
+      {
+        Standard_Integer anIdx = (aCurLoopIt1 + i > aLoop->Length() ? aCurLoopIt1 + i - aLoop->Length() :
+                                  aCurLoopIt1 + i);
+        aMainLoop->InsertAfter (aMainLoopIt1 + i, aLoop->Value (anIdx) * aFactor);
       }
-      loops.Remove(loopNum);
+      aLoops.Remove (aLoopNum1);
     }
   }
-  
-  Standard_Integer stTmp=0;
-  for(i = 1; i <= mainSeq->Length(); i++) {
-    if(i!=mainSeq->Value(i))
-      if(stTmp>=0) stTmp = (mainSeq->Value(i) > 0 ? 1 : -1);
-    myOrd->SetValue(i,mainSeq->Value(i));
+
+  // checking the new order of the edges
+  //  0 - order is the same
+  //  1 - some edges were reordered
+  // -1 - some edges were reversed
+  Standard_Integer aTempStatus = 0;
+  for (Standard_Integer i = 1; i <= aMainLoop->Length(); i++)
+  {
+    if (i != aMainLoop->Value (i) && aTempStatus >= 0)
+    {
+      aTempStatus = (aMainLoop->Value (i) > 0 ? 1 : -1);
+    }
+    myOrd->SetValue (i, aMainLoop->Value (i));
   }
-  if (stTmp == 0) {
-    myStat = stTmp;
+  if (aTempStatus == 0)
+  {
+    myStat = aTempStatus;
     return;
   }
-  else {//check if edges were only shifted in reverse or forward, not reordered
-    Standard_Boolean isShiftReverse = Standard_True, isShiftForward = Standard_True;
-    Standard_Integer tmpFirst = 0, tmpSecond = 0, length = mainSeq->Length();
-    for(i = 1; i <= length - 1; i++) {
-      tmpFirst = mainSeq->Value(i);
-      tmpSecond = mainSeq->Value(i+1);
-      if (!(tmpSecond - tmpFirst == 1 || (tmpFirst == length && tmpSecond == 1)))
+  else
+  {
+    // check if edges were only shifted in reverse or forward, not reordered
+    Standard_Boolean isShiftReverse = Standard_True;
+    Standard_Boolean isShiftForward = Standard_True;
+    Standard_Integer aFirstIdx, aSecondIdx;
+    Standard_Integer aLength = aMainLoop->Length();
+    for (Standard_Integer i = 1; i <= aLength - 1; i++)
+    {
+      aFirstIdx = aMainLoop->Value (i);
+      aSecondIdx = aMainLoop->Value (i + 1);
+      if (!(aSecondIdx - aFirstIdx == 1 || (aFirstIdx == aLength && aSecondIdx == 1)))
+      {
         isShiftForward = Standard_False;
-      if (!(tmpFirst - tmpSecond == 1 || (tmpSecond == length && tmpFirst == 1)))
+      }
+      if (!(aFirstIdx - aSecondIdx == 1 || (aSecondIdx == aLength && aFirstIdx == 1)))
+      {
         isShiftReverse = Standard_False;
+      }
     }
-    tmpFirst = mainSeq->Value(length);
-    tmpSecond = mainSeq->Value(1);
-    if (!(tmpSecond - tmpFirst == 1 || (tmpFirst == length && tmpSecond == 1)))
+    aFirstIdx = aMainLoop->Value (aLength);
+    aSecondIdx = aMainLoop->Value (1);
+    if (!(aSecondIdx - aFirstIdx == 1 || (aFirstIdx == aLength && aSecondIdx == 1)))
+    {
       isShiftForward = Standard_False;
-    if (!(tmpFirst - tmpSecond == 1 || (tmpSecond == length && tmpFirst == 1)))
+    }
+    if (!(aFirstIdx - aSecondIdx == 1 || (aSecondIdx == aLength && aFirstIdx == 1)))
+    {
       isShiftReverse = Standard_False;
+    }
     if (isShiftForward || isShiftReverse)
-      stTmp = 3;
-    myStat = stTmp;
+    {
+      aTempStatus = 3;
+    }
+    myStat = aTempStatus;
     return;
   }
 }
@@ -403,9 +706,9 @@ void ShapeAnalysis_WireOrder::Perform(const Standard_Boolean /*closed*/)
 //purpose  : 
 //=======================================================================
 
- Standard_Boolean ShapeAnalysis_WireOrder::IsDone() const
+Standard_Boolean ShapeAnalysis_WireOrder::IsDone() const
 {
-  return  !myOrd.IsNull();
+  return !myOrd.IsNull();
 }
 
 //=======================================================================
@@ -413,9 +716,9 @@ void ShapeAnalysis_WireOrder::Perform(const Standard_Boolean /*closed*/)
 //purpose  : 
 //=======================================================================
 
- Standard_Integer ShapeAnalysis_WireOrder::Status() const
+Standard_Integer ShapeAnalysis_WireOrder::Status() const
 {
-  return  myStat;
+  return myStat;
 }
 
 //=======================================================================
@@ -423,11 +726,11 @@ void ShapeAnalysis_WireOrder::Perform(const Standard_Boolean /*closed*/)
 //purpose  : 
 //=======================================================================
 
- Standard_Integer ShapeAnalysis_WireOrder::Ordered(const Standard_Integer n) const
+Standard_Integer ShapeAnalysis_WireOrder::Ordered (const Standard_Integer theIdx) const
 {
-  if (myOrd.IsNull() || myOrd->Upper() < n) return n;
-  Standard_Integer ord = myOrd->Value(n);
-  return (ord == 0 ? n : ord);
+  if (myOrd.IsNull() || myOrd->Upper() < theIdx) return theIdx;
+  Standard_Integer anOldIdx = myOrd->Value (theIdx);
+  return (anOldIdx == 0 ? theIdx : anOldIdx);
 }
 
 //=======================================================================
@@ -435,15 +738,10 @@ void ShapeAnalysis_WireOrder::Perform(const Standard_Boolean /*closed*/)
 //purpose  : 
 //=======================================================================
 
- void ShapeAnalysis_WireOrder::XYZ(const Standard_Integer num,gp_XYZ& start3d,gp_XYZ& end3d) const
+void ShapeAnalysis_WireOrder::XYZ (const Standard_Integer theIdx, gp_XYZ& theStart3D, gp_XYZ& theEnd3D) const
 {
-  if (num > 0) {
-    start3d = myXYZ->Value (2*num-1);
-    end3d   = myXYZ->Value (2*num);
-  } else {
-    start3d = myXYZ->Value (-2*num);
-    end3d   = myXYZ->Value (-2*num-1);
-  }
+  theStart3D = myXYZ->Value ((theIdx > 0 ? 2 * theIdx - 1 : -2 * theIdx));
+  theEnd3D = myXYZ->Value ((theIdx > 0 ? 2 * theIdx : -2 * theIdx - 1));
 }
 
 //=======================================================================
@@ -451,12 +749,20 @@ void ShapeAnalysis_WireOrder::Perform(const Standard_Boolean /*closed*/)
 //purpose  : 
 //=======================================================================
 
- void ShapeAnalysis_WireOrder::XY(const Standard_Integer num,gp_XY& start2d,gp_XY& end2d) const
+void ShapeAnalysis_WireOrder::XY (const Standard_Integer theIdx, gp_XY& theStart2D, gp_XY& theEnd2D) const
 {
-  const gp_XYZ& st2d = myXYZ->Value ( (num > 0 ? 2*num-1 : -2*num) );
-  start2d.SetCoord (st2d.X(),st2d.Y());
-  const gp_XYZ& en2d = myXYZ->Value ( (num > 0 ? 2*num   : -2*num -1) );
-  end2d.SetCoord   (en2d.X(),en2d.Y());
+  if (myMode == ModeBoth)
+  {
+    theStart2D = myXY->Value ((theIdx > 0 ? 2 * theIdx - 1 : -2 * theIdx));
+    theEnd2D = myXY->Value ((theIdx > 0 ? 2 * theIdx : -2 * theIdx - 1));
+  }
+  else
+  {
+    const gp_XYZ& aStart3d = myXYZ->Value ((theIdx > 0 ? 2 * theIdx - 1 : -2 * theIdx));
+    theStart2D.SetCoord (aStart3d.X(), aStart3d.Y());
+    const gp_XYZ& anEnd3d = myXYZ->Value ((theIdx > 0 ? 2 * theIdx : -2 * theIdx - 1));
+    theEnd2D.SetCoord (anEnd3d.X(), anEnd3d.Y());
+  }
 }
 
 //=======================================================================
@@ -464,14 +770,14 @@ void ShapeAnalysis_WireOrder::Perform(const Standard_Boolean /*closed*/)
 //purpose  : 
 //=======================================================================
 
- Standard_Real ShapeAnalysis_WireOrder::Gap(const Standard_Integer num) const
+Standard_Real ShapeAnalysis_WireOrder::Gap (const Standard_Integer num) const
 {
   if (num == 0) return myGap;
   Standard_Integer n1 = Ordered (num);
-  Standard_Integer n0 = Ordered (num == 1 ? NbEdges() : num-1);
+  Standard_Integer n0 = Ordered (num == 1 ? NbEdges() : num - 1);
 //  Distance entre fin (n0) et debut (n1)
-  return DISTABS (myXYZ->Value( (n0 > 0 ? 2*n0   : -2*n0 -1) ) ,
-                 myXYZ->Value( (n1 > 0 ? 2*n1-1 : -2*n1   ) ) );
+  return DISTABS (myXYZ->Value ((n0 > 0 ? 2 * n0 : -2 * n0 - 1)),
+                  myXYZ->Value ((n1 > 0 ? 2 * n1 - 1 : -2 * n1)));
 ////  return (myXYZ->Value(2*n0)).Distance (myXYZ->Value(2*n1-1));
 }
 
@@ -480,30 +786,37 @@ void ShapeAnalysis_WireOrder::Perform(const Standard_Boolean /*closed*/)
 //purpose  : 
 //=======================================================================
 
-void ShapeAnalysis_WireOrder::SetChains(const Standard_Real gap) 
+void ShapeAnalysis_WireOrder::SetChains (const Standard_Real gap)
 {
-  Standard_Integer n0 = 0, n1, n2, nb = NbEdges(); //szv#4:S4163:12Mar99 o0,o1,o2 not needed
+  Standard_Integer n0, n1, n2, nb = NbEdges(); //szv#4:S4163:12Mar99 o0,o1,o2 not needed
   if (nb == 0) return;
   TColStd_SequenceOfInteger chain;
   n0 = 0;
   chain.Append (1);    // On demarre la partie
   gp_XYZ f3d, l3d, f13d, l13d; //szv#4:S4163:12Mar99 f03d,l03d unused
-  for (n1 = 1; n1 <= nb; n1 ++) {
-    if (n0 == 0) {    // nouvelle boucle
+  for (n1 = 1; n1 <= nb; n1++)
+  {
+    if (n0 == 0)
+    {    // nouvelle boucle
       n0 = n1;
       //szv#4:S4163:12Mar99 optimized
-      XYZ ( Ordered(n0), f13d, l13d );
+      XYZ (Ordered (n0), f13d, l13d);
     }
     //szv#4:S4163:12Mar99 optimized
-    n2 = (n1 == nb)? n0 : (n1 + 1);
-    XYZ ( Ordered(n2), f3d, l3d );
-    if (!f3d.IsEqual (l13d,gap)) { chain.Append (n2);  n0 = 0; }
-    f13d = f3d;  l13d = l3d;
+    n2 = (n1 == nb) ? n0 : (n1 + 1);
+    XYZ (Ordered (n2), f3d, l3d);
+    if (!f3d.IsEqual (l13d, gap))
+    {
+      chain.Append (n2);
+      n0 = 0;
+    }
+    f13d = f3d;
+    l13d = l3d;
   }
   nb = chain.Length();
   if (nb == 0) return;
-  myChains = new TColStd_HArray1OfInteger (1,nb);
-  for (n1 = 1; n1 <= nb; n1 ++)  myChains->SetValue (n1,chain.Value(n1));
+  myChains = new TColStd_HArray1OfInteger (1, nb);
+  for (n1 = 1; n1 <= nb; n1++) myChains->SetValue (n1, chain.Value (n1));
 }
 
 //=======================================================================
@@ -511,7 +824,7 @@ void ShapeAnalysis_WireOrder::SetChains(const Standard_Real gap)
 //purpose  : 
 //=======================================================================
 
- Standard_Integer ShapeAnalysis_WireOrder::NbChains() const
+Standard_Integer ShapeAnalysis_WireOrder::NbChains() const
 {
   return (myChains.IsNull() ? 0 : myChains->Length());
 }
@@ -521,7 +834,7 @@ void ShapeAnalysis_WireOrder::SetChains(const Standard_Real gap)
 //purpose  : 
 //=======================================================================
 
- void ShapeAnalysis_WireOrder::Chain(const Standard_Integer num,Standard_Integer& n1,Standard_Integer& n2) const
+void ShapeAnalysis_WireOrder::Chain (const Standard_Integer num, Standard_Integer& n1, Standard_Integer& n2) const
 {
   n1 = n2 = 0;
   if (myChains.IsNull()) return;
@@ -529,15 +842,15 @@ void ShapeAnalysis_WireOrder::SetChains(const Standard_Real gap)
   if (num == 0 || num > nb) return;
   n1 = myChains->Value (num);
   if (num == nb) n2 = NbEdges();
-  else n2 = myChains->Value (num+1) - 1;
+  else n2 = myChains->Value (num + 1) - 1;
 }
 
 //=======================================================================
 //function : SetCouples
-//purpose  : 
+//purpose  :
 //=======================================================================
 
- void ShapeAnalysis_WireOrder::SetCouples(const Standard_Real /*gap*/) 
+void ShapeAnalysis_WireOrder::SetCouples (const Standard_Real /*gap*/)
 {
 #ifdef OCCT_DEBUG
   std::cout<<"ShapeAnalysis_WireOrder:SetCouple not yet implemented"<<std::endl;
@@ -546,26 +859,26 @@ void ShapeAnalysis_WireOrder::SetChains(const Standard_Real gap)
 
 //=======================================================================
 //function : NbCouples
-//purpose  : 
+//purpose  :
 //=======================================================================
 
- Standard_Integer ShapeAnalysis_WireOrder::NbCouples() const
+Standard_Integer ShapeAnalysis_WireOrder::NbCouples() const
 {
   return (myCouples.IsNull() ? 0 : myCouples->Length());
 }
 
 //=======================================================================
 //function : Couple
-//purpose  : 
+//purpose  :
 //=======================================================================
 
- void ShapeAnalysis_WireOrder::Couple(const Standard_Integer num,Standard_Integer& n1,Standard_Integer& n2) const
+void ShapeAnalysis_WireOrder::Couple (const Standard_Integer num, Standard_Integer& n1, Standard_Integer& n2) const
 {
   n1 = n2 = 0;
   if (myCouples.IsNull()) return;
   Standard_Integer nb = myCouples->Upper();
-  if (num == 0 || num*2 > nb) return;
-  n1 = myCouples->Value (2*num-1);
-  n2 = myCouples->Value (2*num);
+  if (num == 0 || num * 2 > nb) return;
+  n1 = myCouples->Value (2 * num - 1);
+  n2 = myCouples->Value (2 * num);
 }
 
index 8e2d9cf08483c2420b0dffda6ad757d0edccc98a..cddcc80409d179b877a7012e554fd650ddd28f33 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <Standard_Boolean.hxx>
 #include <TColStd_HArray1OfInteger.hxx>
+#include <TColgp_HSequenceOfXY.hxx>
 #include <TColgp_HSequenceOfXYZ.hxx>
 #include <Standard_Real.hxx>
 #include <Standard_Integer.hxx>
@@ -41,12 +42,10 @@ class gp_XY;
 //! This allows to use this tool, either on existing wire, or on
 //! data just taken from a file (coordinates are easy to get)
 //!
-//! It can work, either in 2D, or in 3D, but not miscible
-//! Warning about tolerance : according to the mode (2D/3D), it
-//! must be given as 2D or 3D (i.e. metric) tolerance, uniform
-//! on the whole list
+//! It can work, either in 2D, or in 3D, or miscible mode
+//! The tolerance for each mode is fixed
 //!
-//! Two phases : firstly add the couples (start,end)
+//! Two phases : firstly add the couples (start, end)
 //! secondly perform then get the result
 class ShapeAnalysis_WireOrder 
 {
@@ -54,17 +53,24 @@ public:
 
   DEFINE_STANDARD_ALLOC
 
-  
   //! Empty constructor
   Standard_EXPORT ShapeAnalysis_WireOrder();
-  
-  //! Creates a WireOrder in 3D (if mode3d is True) or 2D (if False)
-  //! with a tolerance
-  Standard_EXPORT ShapeAnalysis_WireOrder(const Standard_Boolean mode3d, const Standard_Real tol);
-  
-  //! Sets new values. Clears the connexion list
-  //! If <mode3d> changes, also clears the edge list (else, doesn't)
-  Standard_EXPORT void SetMode (const Standard_Boolean mode3d, const Standard_Real tol);
+
+  //! Creates a WireOrder.
+  //! Flag <theMode3D> defines 3D or 2d mode.
+  //! Flag <theModeBoth> defines miscible mode and the flag <theMode3D> is ignored.
+  //! Warning: Parameter <theTolerance> is not used in algorithm.
+  Standard_EXPORT ShapeAnalysis_WireOrder (const Standard_Boolean theMode3D,
+                                           const Standard_Real theTolerance,
+                                           const Standard_Boolean theModeBoth = Standard_False);
+  
+  //! Sets new values.
+  //! Clears the edge list if the mode (<theMode3D> or <theModeBoth> ) changes.
+  //! Clears the connexion list.
+  //! Warning: Parameter <theTolerance> is not used in algorithm.
+  Standard_EXPORT void SetMode (const Standard_Boolean theMode3D,
+                                const Standard_Real theTolerance,
+                                const Standard_Boolean theModeBoth = Standard_False);
   
   //! Returns the working tolerance
   Standard_EXPORT Standard_Real Tolerance() const;
@@ -72,12 +78,18 @@ public:
   //! Clears the list of edges, but not mode and tol
   Standard_EXPORT void Clear();
   
-  //! Adds a couple of points 3D (start,end)
-  Standard_EXPORT void Add (const gp_XYZ& start3d, const gp_XYZ& end3d);
+  //! Adds a couple of points 3D (start, end)
+  Standard_EXPORT void Add (const gp_XYZ& theStart3d, const gp_XYZ& theEnd3d);
   
-  //! Adds a couple of points 2D (start,end)
-  Standard_EXPORT void Add (const gp_XY& start2d, const gp_XY& end2d);
+  //! Adds a couple of points 2D (start, end)
+  Standard_EXPORT void Add (const gp_XY& theStart2d, const gp_XY& theEnd2d);
   
+  //! Adds a couple of points 3D and 2D (start, end)
+  Standard_EXPORT void Add (const gp_XYZ& theStart3d,
+                            const gp_XYZ& theEnd3d,
+                            const gp_XY& theStart2d,
+                            const gp_XY& theEnd2d);
+
   //! Returns the count of added couples of points (one per edges)
   Standard_EXPORT Standard_Integer NbEdges() const;
   
@@ -87,12 +99,11 @@ public:
   Standard_EXPORT Standard_Boolean& KeepLoopsMode();
   
   //! Computes the better order
-  //! If <closed> is True (D) considers also closure
   //! Optimised if the couples were already in order
   //! The criterium is : two couples in order if distance between
   //! end-prec and start-cur is less then starting tolerance <tol>
   //! Else, the smallest distance is reached
-  //! Gap corresponds to a smallest distance greater than <tol>
+  //! Warning: Parameter <closed> not used
   Standard_EXPORT void Perform (const Standard_Boolean closed = Standard_True);
   
   //! Tells if Perform has been done
@@ -102,23 +113,20 @@ public:
   //! Returns the status of the order (0 if not done) :
   //! 0 : all edges are direct and in sequence
   //! 1 : all edges are direct but some are not in sequence
-  //! 2 : in addition, unresolved gaps remain
   //! -1 : some edges are reversed, but no gap remain
-  //! -2 : some edges are reversed and some gaps remain
-  //! -10 : COULD NOT BE RESOLVED, Failure on Reorder
-  //! gap : regarding starting <tol>
+  //! 3 : edges in sequence are just shifted in forward or reverse manner
   Standard_EXPORT Standard_Integer Status() const;
   
   //! Returns the number of original edge which correspond to the
   //! newly ordered number <n>
   //! Warning : the returned value is NEGATIVE if edge should be reversed
-  Standard_EXPORT Standard_Integer Ordered (const Standard_Integer n) const;
+  Standard_EXPORT Standard_Integer Ordered (const Standard_Integer theIdx) const;
   
   //! Returns the values of the couple <num>, as 3D values
-  Standard_EXPORT void XYZ (const Standard_Integer num, gp_XYZ& start3d, gp_XYZ& end3d) const;
+  Standard_EXPORT void XYZ (const Standard_Integer theIdx, gp_XYZ& theStart3D, gp_XYZ& theEnd3D) const;
   
   //! Returns the values of the couple <num>, as 2D values
-  Standard_EXPORT void XY (const Standard_Integer num, gp_XY& start2d, gp_XY& end2d) const;
+  Standard_EXPORT void XY (const Standard_Integer theIdx, gp_XY& theStart2D, gp_XY& theEnd2D) const;
   
   //! Returns the gap between a couple and its preceding
   //! <num> is considered ordered
@@ -135,48 +143,40 @@ public:
   //! Returns, for the chain n0 num, starting and ending numbers of
   //! edges. In the list of ordered edges (see Ordered for originals)
   Standard_EXPORT void Chain (const Standard_Integer num, Standard_Integer& n1, Standard_Integer& n2) const;
-  
+
   //! Determines the couples of edges for which end and start fit
   //! inside a given gap. Queried by NbCouples and Couple
+  //! Warning: function isn't implemented
   Standard_EXPORT void SetCouples (const Standard_Real gap);
-  
+
   //! Returns the count of computed couples
   Standard_EXPORT Standard_Integer NbCouples() const;
-  
+
   //! Returns, for the couple n0 num, the two implied edges
   //! In the list of ordered edges
   Standard_EXPORT void Couple (const Standard_Integer num, Standard_Integer& n1, Standard_Integer& n2) const;
 
-
-
-
 protected:
 
-
-
-
-
 private:
+  // the mode in which the algorithm works
+  enum ModeType
+  {
+    Mode2D,
+    Mode3D,
+    ModeBoth
+  };
 
-
-
-  Standard_Boolean myKeepLoops;
   Handle(TColStd_HArray1OfInteger) myOrd;
   Handle(TColStd_HArray1OfInteger) myChains;
   Handle(TColStd_HArray1OfInteger) myCouples;
   Handle(TColgp_HSequenceOfXYZ) myXYZ;
+  Handle(TColgp_HSequenceOfXY) myXY;
   Standard_Real myTol;
   Standard_Real myGap;
   Standard_Integer myStat;
-  Standard_Boolean myMode;
-
-
+  Standard_Boolean myKeepLoops;
+  ModeType myMode;
 };
 
-
-
-
-
-
-
 #endif // _ShapeAnalysis_WireOrder_HeaderFile
index fcfe71b8e973994b4cc3b3cd75f9052081edb86c..24a8b07caca246f6bdadfc2f247dc2b81176865e 100644 (file)
@@ -349,7 +349,7 @@ Standard_Boolean ShapeFix_Wire::Perform()
   // status even if FixReorder should not be called (if it is forbidden)
 
   ShapeAnalysis_WireOrder sawo;
-  Standard_Boolean ReorderOK = ( myAnalyzer->CheckOrder ( sawo, myClosedMode ) ==0 );
+  Standard_Boolean ReorderOK = (myAnalyzer->CheckOrder( sawo, myClosedMode ) == 0 );
   if ( NeedFix ( myFixReorderMode, ! ReorderOK ) ) { 
     if(FixReorder()) Fixed = Standard_True; 
     ReorderOK = ! StatusReorder ( ShapeExtend_FAIL );
@@ -433,51 +433,53 @@ Standard_Boolean ShapeFix_Wire::Perform()
 //purpose  : 
 //=======================================================================
 
-Standard_Boolean ShapeFix_Wire::FixReorder(
+Standard_Boolean ShapeFix_Wire::FixReorder(Standard_Boolean theModeBoth)
 {
-  myStatusReorder = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
-  if ( ! IsLoaded() ) return Standard_False;
+  myStatusReorder = ShapeExtend::EncodeStatus(ShapeExtend_OK);
+  if (!IsLoaded())
+  {
+    return Standard_False;
+  }
 
-  // fix in 3d
+  // fix in Both mode for bi-periodic surface
   ShapeAnalysis_WireOrder sawo;
-  myAnalyzer->CheckOrder ( sawo, myClosedMode, Standard_True );
-  
-  //:abv revolCuts.sat -23: in case of bi-periodic surface check case
-  // of reversed wire specifically. This is necessary because degenerated
-  // cases are possible when direct evaluation will give bad result.
-  Standard_Boolean isReorder = Standard_False;
-  if ( sawo.Status() != 0 &&
-       ! myAnalyzer->Surface().IsNull() &&
-       myAnalyzer->Surface()->Surface()->IsUPeriodic() &&
-       myAnalyzer->Surface()->Surface()->IsVPeriodic() ) {
-    Handle(ShapeExtend_WireData) sbwd2 = new ShapeExtend_WireData;
-    for ( Standard_Integer i=WireData()->NbEdges(); i >=1; i-- )
-      sbwd2->Add ( WireData()->Edge(i) );
-    ShapeAnalysis_WireOrder sawo2;
-    ShapeAnalysis_Wire analyzer2 ( sbwd2, myAnalyzer->Face(), Precision() );
-    analyzer2.CheckOrder ( sawo2, myClosedMode, Standard_True );
-    if ( ( sawo2.Status() >=0 && sawo2.Status() < sawo.Status() ) || 
-         ( sawo.Status()   <0 && sawo2.Status() > sawo.Status() ) ) {
-      WireData()->Init ( sbwd2 );
-      sawo = sawo2;
-      isReorder = Standard_True;
-    }
-  }
-  
-  FixReorder ( sawo );
-  
-  if ( LastFixStatus ( ShapeExtend_FAIL ) )
-    myStatusReorder |= ShapeExtend::EncodeStatus ( LastFixStatus ( ShapeExtend_FAIL1 ) ? 
-                                                ShapeExtend_FAIL1 : ShapeExtend_FAIL2 );
-  if ( ! LastFixStatus ( ShapeExtend_DONE )&& !isReorder ) return Standard_False;
-  
-  myStatusReorder |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
-  if ( sawo.Status() ==2 || sawo.Status() ==-2 ) 
-    myStatusReorder |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
-  if ( sawo.Status() <0 ) 
-    myStatusReorder |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
-  if ( sawo.Status() == 3)
-    myStatusReorder |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );//only shifted
+  if (!myAnalyzer->Surface().IsNull() &&
+      myAnalyzer->Surface()->Surface()->IsUPeriodic() &&
+      myAnalyzer->Surface()->Surface()->IsVPeriodic() &&
+      theModeBoth)
+  {
+    myAnalyzer->CheckOrder(sawo, myClosedMode, Standard_True, Standard_True);
+  }
+  else
+  {
+    myAnalyzer->CheckOrder(sawo, myClosedMode, Standard_True, Standard_False);
+  }
+
+  FixReorder(sawo);
+
+  if (LastFixStatus(ShapeExtend_FAIL))
+  {
+    myStatusReorder |= ShapeExtend::EncodeStatus(LastFixStatus(ShapeExtend_FAIL1) ? ShapeExtend_FAIL1 : ShapeExtend_FAIL2);
+  }
+  if (!LastFixStatus(ShapeExtend_DONE))
+  {
+    return Standard_False;
+  }
+
+  myStatusReorder |= ShapeExtend::EncodeStatus(ShapeExtend_DONE1);
+  if (sawo.Status() == 2 || sawo.Status() == -2)
+  {
+    myStatusReorder |= ShapeExtend::EncodeStatus(ShapeExtend_DONE2);
+  }
+  if (sawo.Status() < 0)
+  {
+    myStatusReorder |= ShapeExtend::EncodeStatus(ShapeExtend_DONE3);
+  }
+  if (sawo.Status() == 3)
+  {
+    // only shifted
+    myStatusReorder |= ShapeExtend::EncodeStatus(ShapeExtend_DONE5);
+  }
   return Standard_True;
 }
 
index c3fa62a6c431b5227906701f96e0f7b8a523af6b..4539b046b9d2b0b6cc3a5917c9e91c365b91159a 100644 (file)
@@ -267,9 +267,9 @@ public:
   //! FixLacking (if wire is ordered)
   Standard_EXPORT Standard_Boolean Perform();
   
-  //! Performs an analysis and reorders edges in the wire using
-  //! class WireOrder
-  Standard_EXPORT Standard_Boolean FixReorder();
+  //! Performs an analysis and reorders edges in the wire using class WireOrder.
+  //! Flag <theModeBoth> determines the use of miscible mode if necessary.
+  Standard_EXPORT Standard_Boolean FixReorder(Standard_Boolean theModeBoth = Standard_False);
   
   //! Applies FixSmall(num) to all edges in the wire
   Standard_EXPORT Standard_Integer FixSmall (const Standard_Boolean lockvtx, const Standard_Real precsmall = 0.0);
index 5ee5a6e1242f522af0b2077429515fcdf2b08b6c..8189b9efcf8fac85633415a766a1aa6430be64b1 100644 (file)
@@ -72,250 +72,230 @@ TopoDSToStep_MakeStepWire::TopoDSToStep_MakeStepWire
 // Purpose :
 // ----------------------------------------------------------------------------
 
-void TopoDSToStep_MakeStepWire::Init(const TopoDS_Wire& aWire, 
-                                   TopoDSToStep_Tool& aTool,
-                                   const Handle(Transfer_FinderProcess)& FP)
+void TopoDSToStep_MakeStepWire::Init (const TopoDS_Wire& aWire,
+                                      TopoDSToStep_Tool& aTool,
+                                      const Handle(Transfer_FinderProcess)& FP)
 {
-
   // ----------------------------------------------------------------
   // The Wire is given in its relative orientation (i.e. in the face)
   // ----------------------------------------------------------------
+  aTool.SetCurrentWire (aWire);
 
-  aTool.SetCurrentWire(aWire);
-
-  if (aTool.IsBound(aWire)) {
-    myError  = TopoDSToStep_WireDone;
-    done     = Standard_True;
-    myResult = aTool.Find(aWire);
+  if (aTool.IsBound (aWire))
+  {
+    myError = TopoDSToStep_WireDone;
+    done = Standard_True;
+    myResult = aTool.Find (aWire);
     return;
   }
 
-  Standard_Integer i;
-  
-  if (aWire.Orientation() == TopAbs_INTERNAL ||
-      aWire.Orientation() == TopAbs_EXTERNAL ) {
-    Handle(TransferBRep_ShapeMapper) errShape =
-      new TransferBRep_ShapeMapper(aWire);
-    FP->AddWarning(errShape, " Wire(internal/external) from Non Manifold Topology");
+  if (aWire.Orientation() == TopAbs_INTERNAL || aWire.Orientation() == TopAbs_EXTERNAL)
+  {
+    Handle(TransferBRep_ShapeMapper) errShape = new TransferBRep_ShapeMapper (aWire);
+    FP->AddWarning (errShape, " Wire(internal/external) from Non Manifold Topology");
     myError = TopoDSToStep_NonManifoldWire;
-    done    = Standard_False;
+    done = Standard_False;
     return;
   }
 
-  BRepTools_WireExplorer      ItW;
-  TopoDS_Edge                 CurrentEdge;
   TColStd_SequenceOfTransient mySeq;
-  
+
   // --------
   // Polyloop
   // --------
-  
-  if (aTool.Faceted()) {
-    Handle(StepShape_VertexPoint)                   VertexPoint;
-    Handle(StepGeom_Point)                         Point;
+  if (aTool.Faceted())
+  {
+    Handle(StepShape_VertexPoint) VertexPoint;
+    Handle(StepGeom_Point) Point;
     Handle(StepShape_TopologicalRepresentationItem) Gpms;
-    TopoDS_Vertex                               TopoDSVertex1, TopoDSVertex2;
-    
+    TopoDS_Vertex TopoDSVertex1, TopoDSVertex2;
+
     TopoDSToStep_MakeStepVertex MkVertex;
-//    TopoDS_Wire ForwardWire = TopoDS::Wire(aWire.Oriented(TopAbs_FORWARD));
-    
-    for (ItW.Init(aWire, aTool.CurrentFace()); 
-        ItW.More();ItW.Next()) {
-      CurrentEdge = ItW.Current();
+
+    for (BRepTools_WireExplorer ItW (aWire, aTool.CurrentFace()); ItW.More(); ItW.Next())
+    {
+      const TopoDS_Edge& CurrentEdge = ItW.Current();
       if (CurrentEdge.Orientation() == TopAbs_FORWARD)
-       TopExp::Vertices(CurrentEdge, TopoDSVertex1, TopoDSVertex2);
-      else 
-       TopExp::Vertices(CurrentEdge, TopoDSVertex2, TopoDSVertex1);
-      
-      MkVertex.Init(TopoDSVertex1, aTool, FP);
-      if (MkVertex.IsDone()) {
-       VertexPoint = Handle(StepShape_VertexPoint)::DownCast(MkVertex.Value());
-       Point = VertexPoint->VertexGeometry();
-       mySeq.Append(Point);
+      {
+        TopExp::Vertices (CurrentEdge, TopoDSVertex1, TopoDSVertex2);
       }
-      else {
-       Handle(TransferBRep_ShapeMapper) errShape =
-         new TransferBRep_ShapeMapper(aWire);
-       FP->AddWarning(errShape, " a Vertex Point not mapped");
-       myError = TopoDSToStep_WireOther;
-       done = Standard_False;
-       return;
+      else
+      {
+        TopExp::Vertices (CurrentEdge, TopoDSVertex2, TopoDSVertex1);
+      }
+
+      MkVertex.Init (TopoDSVertex1, aTool, FP);
+      if (MkVertex.IsDone())
+      {
+        VertexPoint = Handle(StepShape_VertexPoint)::DownCast (MkVertex.Value());
+        Point = VertexPoint->VertexGeometry();
+        mySeq.Append (Point);
+      }
+      else
+      {
+        Handle(TransferBRep_ShapeMapper) errShape = new TransferBRep_ShapeMapper (aWire);
+        FP->AddWarning (errShape, " a Vertex Point not mapped");
+        myError = TopoDSToStep_WireOther;
+        done = Standard_False;
+        return;
       }
     }
     Standard_Integer nbPoints = mySeq.Length();
-    if (nbPoints>=3) {
-      Handle(StepGeom_HArray1OfCartesianPoint) aPolygon =
-       new StepGeom_HArray1OfCartesianPoint(1,nbPoints);
-      for ( i=1; i<=nbPoints; i++) {
-       aPolygon->SetValue(i, Handle(StepGeom_CartesianPoint)::
-                          DownCast(mySeq.Value(i))); 
+    if (nbPoints >= 3)
+    {
+      Handle(StepGeom_HArray1OfCartesianPoint) aPolygon = new StepGeom_HArray1OfCartesianPoint (1, nbPoints);
+      for (Standard_Integer i = 1; i <= nbPoints; i++)
+      {
+        aPolygon->SetValue (i, Handle(StepGeom_CartesianPoint)::DownCast (mySeq.Value (i)));
       }
       Handle(StepShape_PolyLoop) PL = new StepShape_PolyLoop();
-      Handle(TCollection_HAsciiString) aName = 
-       new TCollection_HAsciiString("");
-      PL->Init(aName, aPolygon);
-      
-      aTool.Bind(aWire, PL);
-      myError  = TopoDSToStep_WireDone;
-      done     = Standard_True;
+      Handle(TCollection_HAsciiString) aName = new TCollection_HAsciiString ("");
+      PL->Init (aName, aPolygon);
+
+      aTool.Bind (aWire, PL);
+      myError = TopoDSToStep_WireDone;
+      done = Standard_True;
       myResult = PL;
       return;
     }
-    else {
-      Handle(TransferBRep_ShapeMapper) errShape =
-       new TransferBRep_ShapeMapper(aWire);
-      FP->AddWarning(errShape, " PolyLoop: Wire has less than 3 points");
+    else
+    {
+      Handle(TransferBRep_ShapeMapper) errShape = new TransferBRep_ShapeMapper (aWire);
+      FP->AddWarning (errShape, " PolyLoop: Wire has less than 3 points");
       myError = TopoDSToStep_WireOther;
       done = Standard_False;
       return;
     }
   }
-  
-  // --------
-  // EdgeLoop
-  // --------
-  
-  else {
-
+    // --------
+    // EdgeLoop
+    // --------
+  else
+  {
     Handle(StepShape_TopologicalRepresentationItem) Gpms;
-    Handle(StepShape_Edge)                          Epms;
-    Handle(StepShape_OrientedEdge)                  OrientedEdge;
-    
+    Handle(StepShape_Edge) Epms;
+    Handle(StepShape_OrientedEdge) OrientedEdge;
     TopoDSToStep_MakeStepEdge MkEdge;
 
-    //szv#4:S4163:12Mar99 SGI warns
-    TopoDS_Shape sh = aWire.Oriented(TopAbs_FORWARD);
-    const TopoDS_Wire ForwardWire = TopoDS::Wire(sh);
-    // test 25-01-96 FMA  supprime CKY 2-JUN-1997, cf MakeStepFace->Face FWD]
-    // remis CKY 9-DEC-1997 : chaque niveau se traite en FWD
-//#11 rln 16/03/98
-//TestRally8 file carter2.rle face#333 (wire is not sorted, not sorted edges are seam and iso-curve):
-//aWire is REVERSED but ForwardWire is FORWARD, when exploding not connected seams their pcurves are
-//returned in incorrect order (because of mismatched orientation)
-//As a result not sorted edges are lost (not returned by BRepTools_WireExplorer)
-//By the way, in the case of aTool.Faceted() aWire is used
+    const TopoDS_Wire ForwardWire = TopoDS::Wire (aWire.Oriented (TopAbs_FORWARD));
+    Handle(ShapeFix_Wire) STW = new ShapeFix_Wire (ForwardWire, aTool.CurrentFace(), Precision::Confusion());
+    // for toroidal like surfaces we need to use both (3d and 2d) mode to correctly reorder the edges
+    STW->FixReorder (Standard_True);
+    Handle(ShapeExtend_WireData) anExtWire = STW->WireData();
 
-//#11 ItW.Init(ForwardWire, aTool.CurrentFace());
-//#11 for (;ItW.More();ItW.Next()) {
-    Handle(ShapeFix_Wire) STW =
-      new ShapeFix_Wire(ForwardWire, aTool.CurrentFace(), Precision::Confusion());
-    STW->FixReorder();
-    Handle(ShapeExtend_WireData) sbwd = STW->WireData();
-    Standard_Integer nb = sbwd->NbEdges();
-    
     //:abv 04.05.00: CAX-IF TRJ4: writing complete sphere with single vertex_loop
     // check that whole wire is one seam (perhaps made of several seam edges)
     //pdn remove degenerated pcurves
-    Handle(ShapeExtend_WireData) cwd = new ShapeExtend_WireData;
-    Standard_Integer ie;
-    for (ie = 1; ie <=nb; ie++) {
-      TopoDS_Edge edge = sbwd->Edge(ie);
-      if (!BRep_Tool::Degenerated(edge))
-       cwd->Add(edge);
-    }
 
-    nb = cwd->NbEdges();
-    if(nb%2 == 0 ) {
-      for ( ie = 1; ie < nb; ie++) {
-       if ( cwd->Edge(ie).IsSame(cwd->Edge(ie+1)) ) break;
+    // collect not degenerated edges
+    Handle(ShapeExtend_WireData) anExtWire2 = new ShapeExtend_WireData;
+    for (Standard_Integer ie = 1; ie <= anExtWire->NbEdges(); ie++)
+    {
+      TopoDS_Edge anEdge = anExtWire->Edge (ie);
+      if (!BRep_Tool::Degenerated (anEdge))
+      {
+        anExtWire2->Add (anEdge);
       }
-      if ( ie < nb ) {
-       cwd->SetLast(ie);
-       for ( ie=nb/2+1; ie <= nb; ie++ ) {
-         if ( ! cwd->Edge(ie).IsSame(cwd->Edge(nb-ie+1)) ) break;
-       }
-       if ( ie > nb ) { // make vertex_loop
-         ShapeAnalysis_Edge sae;
-         TopoDS_Vertex V = sae.FirstVertex(cwd->Edge(1));
-         TopoDSToStep_MakeStepVertex mkV ( V, aTool, FP );
-         Handle(StepShape_VertexLoop) vloop = new StepShape_VertexLoop;
-         Handle(TCollection_HAsciiString) name = new TCollection_HAsciiString ( "" );
-         vloop->Init ( name, Handle(StepShape_Vertex)::DownCast ( mkV.Value() ) );
-         aTool.Bind(aWire, vloop);
-         myError  = TopoDSToStep_WireDone;
-         done     = Standard_True;
-         myResult = vloop;
-         return;
-       }
+    }
+    // check for seam edges
+    Standard_Integer nb = anExtWire2->NbEdges();
+    if (nb % 2 == 0)
+    {
+      Standard_Integer ie;
+      // check if two adjacent edges are the same
+      for (ie = 1; ie < nb; ie++)
+      {
+        if (anExtWire2->Edge (ie).IsSame (anExtWire2->Edge (ie + 1)))
+        {
+          break;
+        }
+      }
+      // if found seam edges
+      if (ie < nb)
+      {
+        // make the first edge from pair last
+        anExtWire2->SetLast (ie);
+        for (ie = nb / 2 + 1; ie <= nb; ie++)
+        {
+          if (!anExtWire2->Edge (ie).IsSame (anExtWire2->Edge (nb - ie + 1)))
+          {
+            break;
+          }
+        }
+        if (ie > nb)
+        {
+          // make vertex_loop
+          ShapeAnalysis_Edge sae;
+          TopoDS_Vertex V = sae.FirstVertex (anExtWire2->Edge (1));
+          TopoDSToStep_MakeStepVertex mkV (V, aTool, FP);
+          Handle(StepShape_VertexLoop) vloop = new StepShape_VertexLoop;
+          Handle(TCollection_HAsciiString) name = new TCollection_HAsciiString ("");
+          vloop->Init (name, Handle(StepShape_Vertex)::DownCast (mkV.Value()));
+          aTool.Bind (aWire, vloop);
+          myError = TopoDSToStep_WireDone;
+          done = Standard_True;
+          myResult = vloop;
+          return;
+        }
       }
     }
-    nb = sbwd->NbEdges();
-    
-    for (Standard_Integer nEdge = 1; nEdge <= sbwd->NbEdges(); nEdge++) {
-  
-      CurrentEdge = sbwd->Edge(nEdge);
-//#11 CurrentEdge = ItW.Current();
-      
-      //if (ItW.Current().Orientation() != ItW.Orientation())
-      //std::cout << "DEBUG : Attention WireExplorer Orientation" << std::endl;
 
+    for (Standard_Integer nEdge = 1; nEdge <= anExtWire->NbEdges(); nEdge++)
+    {
+      const TopoDS_Edge anEdge = anExtWire->Edge (nEdge);
       // ---------------------------------
       // --- Is the edge Degenerated ? ---
       // ---------------------------------
-
       Standard_Real cf, cl;
-      Handle(Geom2d_Curve) theC2d = 
-       BRep_Tool::CurveOnSurface(CurrentEdge, aTool.CurrentFace(), cf, cl);
-      //BRepAdaptor_Curve CA;
-      //CA = BRepAdaptor_Curve(CurrentEdge, 
-      //aTool.CurrentFace());
-      //GeomAbs_CurveType typC = CA.CurveOnSurface().GetCurve().GetType();
-      //if (typC == GeomAbs_Line && BRep_Tool::Degenerated(CurrentEdge)) {
-       //Handle(TransferBRep_ShapeMapper) errShape =
-         //new TransferBRep_ShapeMapper(aWire);
-       //FP->AddWarning(errShape, " EdgeLoop: Degenerated Pcurve not mapped");
-      //}
-      if ( //:abv 26Jan00, CAX-IF TRJ3: ! theC2d.IsNull() && theC2d->IsKind(STANDARD_TYPE(Geom2d_Line)) && 
-         BRep_Tool::Degenerated(CurrentEdge)) {
-       Handle(TransferBRep_ShapeMapper) errShape =
-         new TransferBRep_ShapeMapper(aWire);
-       FP->AddWarning(errShape, " EdgeLoop: Degenerated Pcurve not mapped");
-       continue;
+      Handle(Geom2d_Curve) theC2d = BRep_Tool::CurveOnSurface (anEdge, aTool.CurrentFace(), cf, cl);
+      if (BRep_Tool::Degenerated (anEdge))
+      {
+        Handle(TransferBRep_ShapeMapper) errShape = new TransferBRep_ShapeMapper (aWire);
+        FP->AddWarning (errShape, " EdgeLoop: Degenerated Pcurve not mapped");
+        continue;
       }
-      else {
-       //szv#4:S4163:12Mar99 SGI warns
-       //TopoDS_Shape ssh = CurrentEdge.Oriented(TopAbs_FORWARD);
-       //const TopoDS_Edge ForwardEdge = TopoDS::Edge(ssh);
-
-       MkEdge.Init(CurrentEdge, aTool, FP);
-       if (MkEdge.IsDone()) {
-         OrientedEdge = new StepShape_OrientedEdge();
-         Epms = Handle(StepShape_Edge)::DownCast(MkEdge.Value());
-         Handle(TCollection_HAsciiString) aName = new TCollection_HAsciiString("");
-         OrientedEdge->Init(aName, Epms, (CurrentEdge.Orientation() == TopAbs_FORWARD));
-         mySeq.Append(OrientedEdge);
-       }
-       else {
-         Handle(TransferBRep_ShapeMapper) errShape =
-           new TransferBRep_ShapeMapper(aWire);
-         FP->AddWarning(errShape, " EdgeLoop: an Edge not mapped");
-         myError = TopoDSToStep_WireOther;
-         done    = Standard_False;
-         return;
-       }
+      else
+      {
+        MkEdge.Init (anEdge, aTool, FP);
+        if (MkEdge.IsDone())
+        {
+          OrientedEdge = new StepShape_OrientedEdge();
+          Epms = Handle(StepShape_Edge)::DownCast (MkEdge.Value());
+          Handle(TCollection_HAsciiString) aName = new TCollection_HAsciiString ("");
+          OrientedEdge->Init (aName, Epms, (anEdge.Orientation() == TopAbs_FORWARD));
+          mySeq.Append (OrientedEdge);
+        }
+        else
+        {
+          Handle(TransferBRep_ShapeMapper) errShape = new TransferBRep_ShapeMapper (aWire);
+          FP->AddWarning (errShape, " EdgeLoop: an Edge not mapped");
+          myError = TopoDSToStep_WireOther;
+          done = Standard_False;
+          return;
+        }
       }
     }
     Standard_Integer nbEdges = mySeq.Length();
-    if ( nbEdges >0 ) {
-      Handle(StepShape_HArray1OfOrientedEdge) aList =
-       new StepShape_HArray1OfOrientedEdge(1,nbEdges);
-      for ( i=1; i<=nbEdges; i++ ) {
-       aList->SetValue(i, Handle(StepShape_OrientedEdge)::
-                       DownCast(mySeq.Value(i))); 
+    if (nbEdges > 0)
+    {
+      Handle(StepShape_HArray1OfOrientedEdge) aList = new StepShape_HArray1OfOrientedEdge (1, nbEdges);
+      for (Standard_Integer i = 1; i <= nbEdges; i++)
+      {
+        aList->SetValue (i, Handle(StepShape_OrientedEdge)::
+        DownCast (mySeq.Value (i)));
       }
       Handle(StepShape_EdgeLoop) Epmsl = new StepShape_EdgeLoop;
-      Handle(TCollection_HAsciiString) aName = 
-       new TCollection_HAsciiString("");
-      Epmsl->Init(aName, aList);
-      aTool.Bind(aWire, Epmsl);
+      Handle(TCollection_HAsciiString) aName = new TCollection_HAsciiString ("");
+      Epmsl->Init (aName, aList);
+      aTool.Bind (aWire, Epmsl);
       done = Standard_True;
-      myResult = Epmsl;   
+      myResult = Epmsl;
       return;
     }
-    else {
-      Handle(TransferBRep_ShapeMapper) errShape =
-       new TransferBRep_ShapeMapper(aWire);
-      FP->AddWarning(errShape, " No Edges of this Wire were mapped");
+    else
+    {
+      Handle(TransferBRep_ShapeMapper) errShape = new TransferBRep_ShapeMapper (aWire);
+      FP->AddWarning (errShape, " No Edges of this Wire were mapped");
       myError = TopoDSToStep_WireOther;
       done = Standard_False;
       return;
index da63f8e664f5a53e300c948e3634f283f2d72ff0..7230283640d93da1fc989ecf18af40ce6535c2f1 100644 (file)
@@ -13,7 +13,7 @@ checkprops result -s 1.8e+101
 
 set nbshapes_expected "
 Number of shapes in shape
- VERTEX    : 56881
+ VERTEX    : 56883
  EDGE      : 85310
  WIRE      : 37795
  FACE      : 32992
@@ -21,7 +21,7 @@ Number of shapes in shape
  SOLID     : 1308
  COMPSOLID : 0
  COMPOUND  : 1
- SHAPE     : 215605
+ SHAPE     : 215607
 "
 checknbshapes result -ref ${nbshapes_expected} -t -m "importing file"
 checkview -display result -3d -path ${imagedir}/${test_image}.png
\ No newline at end of file
diff --git a/tests/bugs/step/bug32922 b/tests/bugs/step/bug32922
new file mode 100644 (file)
index 0000000..ed26939
--- /dev/null
@@ -0,0 +1,111 @@
+puts "============"
+puts "OCC32922 Data Exchange, STEP - The torus is stored incorrectly in STEP format"
+puts "============"
+puts ""
+#####################################################
+# STEP testing the case when a torus is saved in STEP
+# format with an incorrect edge order
+#####################################################
+
+pload MODELING XDE
+
+if { [info exists imagedir] == 0 } {
+   set imagedir ../bug32922
+   if {![file exists ${imagedir}]} {
+       file mkdir ${imagedir}
+   }
+}
+
+# Generating resource file where all shape healing is off
+set fdata {
+ToSTEP.exec.op : SplitCommonVertex,DirectFaces
+
+FromSTEP.exec.op : FixShape
+
+FromSTEP.FixShape.Tolerance3d                         : &Runtime.Tolerance
+FromSTEP.FixShape.MaxTolerance3d                      : &Runtime.MaxTolerance
+FromSTEP.FixShape.MinTolerance3d                      : 1.e-7
+FromSTEP.FixShape.FixFreeShellMode                    : 0
+FromSTEP.FixShape.FixFreeFaceMode                     : 0
+FromSTEP.FixShape.FixFreeWireMode                     : 0
+FromSTEP.FixShape.FixSameParameterMode                : 0
+
+FromSTEP.FixShape.FixSolidMode                        : 0
+FromSTEP.FixShape.FixShellOrientationMode             : 0
+FromSTEP.FixShape.CreateOpenSolidMode                 : 0
+
+FromSTEP.FixShape.FixShellMode                        : 0
+FromSTEP.FixShape.FixFaceOrientationMode              : 0
+
+FromSTEP.FixShape.FixFaceMode                         : 0
+FromSTEP.FixShape.FixWireMode                         : 0
+FromSTEP.FixShape.FixOrientationMode                  : 0
+FromSTEP.FixShape.FixAddNaturalBoundMode              : 0
+FromSTEP.FixShape.FixMissingSeamMode                  : 0
+FromSTEP.FixShape.FixSmallAreaWireMode                : 0
+FromSTEP.FixShape.RemoveSmallAreaFaceMode             : 0
+FromSTEP.FixShape.FixIntersectingWiresMode            : 0
+FromSTEP.FixShape.FixLoopWiresMode                    : 0
+FromSTEP.FixShape.FixSplitFaceMode                    : 0
+FromSTEP.FixShape.AutoCorrectPrecisionMode            : 0
+FromSTEP.FixShape.ModifyTopologyMode                  : 0
+FromSTEP.FixShape.ModifyGeometryMode                  : 0
+FromSTEP.FixShape.ClosedWireMode                      : 0
+FromSTEP.FixShape.PreferencePCurveMode                : 0
+FromSTEP.FixShape.FixReorderMode                      : 0
+FromSTEP.FixShape.FixSmallMode                        : 0
+FromSTEP.FixShape.FixConnectedMode                    : 0
+FromSTEP.FixShape.FixEdgeCurvesMode                   : 0
+FromSTEP.FixShape.FixDegeneratedMode                  : 0
+FromSTEP.FixShape.FixLackingMode                      : 0
+FromSTEP.FixShape.FixSelfIntersectionMode             : 0
+FromSTEP.FixShape.RemoveLoopMode                      : 0
+FromSTEP.FixShape.FixReversed2dMode                   : 0
+FromSTEP.FixShape.FixRemovePCurveMode                 : 0
+FromSTEP.FixShape.FixRemoveCurve3dMode                : 0
+FromSTEP.FixShape.FixAddPCurveMode                    : 0
+FromSTEP.FixShape.FixAddCurve3dMode                   : 0
+FromSTEP.FixShape.FixSeamMode                         : 0
+FromSTEP.FixShape.FixShiftedMode                      : 0
+FromSTEP.FixShape.FixEdgeSameParameterMode            : 0
+FromSTEP.FixShape.FixNotchedEdgesMode                 : 0
+FromSTEP.FixShape.FixTailMode                         : 0
+FromSTEP.FixShape.MaxTailAngle                        : 0
+FromSTEP.FixShape.MaxTailWidth                        : 0
+FromSTEP.FixShape.FixSelfIntersectingEdgeMode         : 0
+FromSTEP.FixShape.FixIntersectingEdgesMode            : 0
+FromSTEP.FixShape.FixNonAdjacentIntersectingEdgesMode : 0
+
+FromSTEP.FixShape.FixVertexPositionMode               : 0
+FromSTEP.FixShape.FixVertexToleranceMode              : 0
+}
+
+set new_resource_path ${imagedir}
+set resource_file STEP
+set fo [open "${new_resource_path}/${resource_file}" "wb"]
+puts -nonewline $fo $fdata
+close $fo
+
+# Changing the path to the resource file
+set old_resource_path $::env(CSF_STEPDefaults)
+set env(CSF_STEPDefaults) ${new_resource_path}
+
+# Generating, writing and reading the torus
+ptorus tor 20 5
+set step_file ${imagedir}/torus.stp
+testwritestep ${step_file} tor
+stepread ${step_file} a *
+
+# Cheking the face of the torus
+explode a_1 f
+renamevar a_1_1 result
+checkshape result
+
+# Making screenshort
+pcurve result
+view 1 -2D- 728 20 400 400
+2dfit
+checkview -screenshot -2d -path ${imagedir}/${test_image}.png
+
+# Restoring the path to the old resource file
+set env(CSF_STEPDefaults) ${old_resource_path}