0030348: Shape Healing - ShapeFix_Wire::FixEdgeCurves() throws Standard_OutOfRange...
[occt.git] / src / ShapeFix / ShapeFix_Wire.cxx
index af37d90..4bb06b1 100644 (file)
 #include <TopTools_Array1OfShape.hxx>
 #include <TopTools_HSequenceOfShape.hxx>
 
+IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Wire,ShapeFix_Root)
+
 //S4135
 //#######################################################################
 //  Constructors, initializations, modes, querying
@@ -341,7 +343,7 @@ Standard_Boolean ShapeFix_Wire::Perform()
   if ( !Context().IsNull() )
     myFixEdge->SetContext( Context() );
 
-  Standard_Integer Fixed = Standard_False;
+  Standard_Boolean Fixed = Standard_False;
   
   // FixReorder is first, because as a rule wire is required to be ordered
   // We shall analyze the order of edges in the wire and set appropriate 
@@ -416,7 +418,7 @@ Standard_Boolean ShapeFix_Wire::Perform()
   // TEMPORARILY without special mode !!!
   Handle(ShapeExtend_WireData) sbwd = WireData();
   for (Standard_Integer iedge = 1; iedge <= sbwd->NbEdges(); iedge++)
-    if ( myFixEdge->FixVertexTolerance (sbwd->Edge (iedge)) ) 
+    if ( myFixEdge->FixVertexTolerance (sbwd->Edge (iedge), Face()) ) 
     {
       Fixed = Standard_True;
     }
@@ -533,7 +535,7 @@ Standard_Boolean ShapeFix_Wire::FixEdgeCurves()
   Handle(ShapeExtend_WireData) sbwd = WireData();
   Standard_Integer i, nb = sbwd->NbEdges();
   TopoDS_Face face = Face();
-  Handle(ShapeFix_Edge) theAdvFixEdge = Handle(ShapeFix_Edge)::DownCast(myFixEdge);
+  Handle(ShapeFix_Edge) theAdvFixEdge = myFixEdge;
   if (theAdvFixEdge.IsNull()) myFixReversed2dMode = Standard_False;
 
   // fix revesred 2d / 3d curves
@@ -755,7 +757,14 @@ Standard_Boolean ShapeFix_Wire::FixEdgeCurves()
           sbwd->Remove ( i-- );
           nb--;
           myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
-          FixConnected (i + 1, Precision());
+          if (i == nb)
+          {
+            FixClosed (Precision());
+          }
+          else
+          {
+            FixConnected (i + 1, Precision());
+          }
         }
        myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL5 );
       }
@@ -792,15 +801,29 @@ Standard_Boolean ShapeFix_Wire::FixEdgeCurves()
       if(sae.HasPCurve(sbwd->Edge(i),face)) {
         Handle(Geom2d_Curve) C2d;
         Standard_Real fp2d,lp2d;
-        if(sae.PCurve(sbwd->Edge(i),face,C2d,fp2d,lp2d)) {
+        if(sae.PCurve(sbwd->Edge(i),face,C2d,fp2d,lp2d, Standard_False)) {
           if( fabs(First-fp2d)>Precision::PConfusion() ||
-              fabs(Last-lp2d)>Precision::PConfusion() ) {
+              fabs(Last-lp2d)>Precision::PConfusion()    ) 
+          {
             BRep_Builder B;
             B.SameRange(sbwd->Edge(i),Standard_False);
           }
+          else if(!sae.CheckPCurveRange(First, Last, C2d))
+          {
+            //Replace pcurve
+            TopLoc_Location L;
+            const Handle(Geom_Surface)& S = BRep_Tool::Surface(face, L);
+            ShapeBuild_Edge().RemovePCurve (sbwd->Edge(i),  S, L);
+            myFixEdge->FixAddPCurve ( sbwd->Edge(i), face, sbwd->IsSeam(i), 
+                        myAnalyzer->Surface(), Precision() );
+            if ( myFixEdge->Status ( ShapeExtend_DONE ) ) 
+              myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
+            if ( myFixEdge->Status ( ShapeExtend_FAIL ) ) 
+              myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL3 );
+          }
         }
       }
-      myFixEdge->FixSameParameter ( sbwd->Edge(i) );
+      myFixEdge->FixSameParameter ( sbwd->Edge(i), Face());
       if ( myFixEdge->Status ( ShapeExtend_DONE ) ) 
        myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
       if ( myFixEdge->Status ( ShapeExtend_FAIL ) ) 
@@ -814,7 +837,7 @@ Standard_Boolean ShapeFix_Wire::FixEdgeCurves()
   {
     for ( i=1; i <= nb; i++)
     {
-      myFixEdge->FixVertexTolerance (sbwd->Edge (i), face);
+      myFixEdge->FixVertexTolerance (sbwd->Edge (i), Face());
       if ( myFixEdge->Status ( ShapeExtend_DONE ) ) 
         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
       if ( myFixEdge->Status ( ShapeExtend_FAIL ) ) 
@@ -897,24 +920,27 @@ Standard_Boolean ShapeFix_Wire::FixSelfIntersection()
     }
   }
   
-  if ( NeedFix ( myFixIntersectingEdgesMode ) ) {
+  if ( NeedFix ( myFixIntersectingEdgesMode ) )
+  {
     Standard_Integer num = ( myClosedMode ? 1 : 2 );
-    for ( ; nb >1 && num <= nb; num++ ) {
+    for ( ; nb >1 && num <= nb; num++ )
+    {
       FixIntersectingEdges ( num );
       if ( LastFixStatus ( ShapeExtend_FAIL1 ) ) 
-       myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
+        myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
       if ( LastFixStatus ( ShapeExtend_FAIL2 ) ) 
-       myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
+        myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
       if ( ! LastFixStatus ( ShapeExtend_DONE ) ) continue;
 
       if ( LastFixStatus ( ShapeExtend_DONE1 ) ) 
-       myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
+        myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
       if ( LastFixStatus ( ShapeExtend_DONE2 ) ) 
-       myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
+        myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
       if(LastFixStatus (ShapeExtend_DONE6))
-  myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE6 );
+        myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE6 );
 
-      if ( /*! myTopoMode ||*/ nb < 3 ) {
+      if ( /*! myTopoMode ||*/ nb < 3 )
+      {
         //#86 rln 22.03.99 sim2.igs, entity 4292: After fixing of self-intersecting
         //BRepCheck finds one more self-intersection not found by ShapeAnalysis
         //%15 pdn 06.04.99 repeat until fixed CTS18546-2 entity 777
@@ -928,25 +954,30 @@ Standard_Boolean ShapeFix_Wire::FixSelfIntersection()
       if ( LastFixStatus ( ShapeExtend_DONE4 ) ) sbwd->Remove ( num );
       if ( LastFixStatus ( ShapeExtend_DONE3 ) ) sbwd->Remove ( num >1 ? num-1 : nb+num-1 );
       if ( LastFixStatus ( ShapeExtend_DONE4 ) ||
-           LastFixStatus ( ShapeExtend_DONE3 ) ) {
-       myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
-       num = ( myClosedMode ? 1 : 2 );
-       nb = sbwd->NbEdges();
+           LastFixStatus ( ShapeExtend_DONE3 ) )
+      {
+        myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
+        num = ( myClosedMode ? 1 : 2 );
+        nb = sbwd->NbEdges();
 #ifdef OCCT_DEBUG
-       cout << "Warning: ShapeFix_Wire::FixSelfIntersection: Edge removed" << endl;
+        cout << "Warning: ShapeFix_Wire::FixSelfIntersection: Edge removed" << endl;
 #endif
       }
-      else {
-       //#86 rln 22.03.99
-       //%15 pdn 06.04.99 repeat until fixed CTS18546-2 entity 777
-       FixIntersectingEdges ( num );
-       /*if ( LastFixStatus ( ShapeExtend_DONE7 ) )*/
+      else
+      {
+        //#86 rln 22.03.99
+        //%15 pdn 06.04.99 repeat until fixed CTS18546-2 entity 777
+        FixIntersectingEdges ( num );
+        /*if ( LastFixStatus ( ShapeExtend_DONE7 ) )*/
         // Always revisit the fixed edge
         //num--;
       }
     }
+    if ( !Context().IsNull())
+      UpdateWire();
   }
 
+
   //pdn 17.03.99 S4135 to avoid regression fixing not adjacent intersection
   if ( NeedFix ( myFixNonAdjacentIntersectingEdgesMode ) ) {
 
@@ -1132,7 +1163,7 @@ Standard_Boolean ShapeFix_Wire::FixSmall (const Standard_Integer num,
   if ( ! IsLoaded() || NbEdges() <=1 ) return Standard_False;
 
   // analysis:
-  Handle(ShapeAnalysis_Wire) theAdvAnalyzer = Handle(ShapeAnalysis_Wire)::DownCast(myAnalyzer);
+  Handle(ShapeAnalysis_Wire) theAdvAnalyzer = myAnalyzer;
   if (theAdvAnalyzer.IsNull()) return Standard_False;
   Standard_Integer n = ( num >0 ? num : NbEdges() );
   theAdvAnalyzer->CheckSmall ( n, precsmall );
@@ -1778,7 +1809,7 @@ static Standard_Boolean TryNewPCurve (const TopoDS_Edge &E, const TopoDS_Face &f
 // no call to BRepLib:  B.SameParameter ( edge, Standard_False );
 
   Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
-  sfe->FixSameParameter ( edge ); 
+  sfe->FixSameParameter ( edge, face ); 
   c2d = BRep_Tool::CurveOnSurface ( edge, face, first, last );
   tol = BRep_Tool::Tolerance ( edge );
   return Standard_True;
@@ -2180,7 +2211,7 @@ Standard_Boolean ShapeFix_Wire::FixSelfIntersectingEdge (const Standard_Integer
   // analysis
   IntRes2d_SequenceOfIntersectionPoint points2d;
   TColgp_SequenceOfPnt points3d;
-  Handle(ShapeAnalysis_Wire) theAdvAnalyzer =  Handle(ShapeAnalysis_Wire)::DownCast(myAnalyzer);
+  Handle(ShapeAnalysis_Wire) theAdvAnalyzer = myAnalyzer;
   if (theAdvAnalyzer.IsNull()) return Standard_False;
   theAdvAnalyzer->CheckSelfIntersectingEdge ( num, points2d, points3d ); 
   if ( theAdvAnalyzer->LastCheckStatus ( ShapeExtend_FAIL ) ) {
@@ -2375,7 +2406,7 @@ Standard_Boolean ShapeFix_Wire::FixIntersectingEdges (const Standard_Integer num
   IntRes2d_SequenceOfIntersectionPoint points2d;
   TColgp_SequenceOfPnt points3d;
   TColStd_SequenceOfReal errors;
-  Handle(ShapeAnalysis_Wire) theAdvAnalyzer = Handle(ShapeAnalysis_Wire)::DownCast(myAnalyzer);
+  Handle(ShapeAnalysis_Wire) theAdvAnalyzer = myAnalyzer;
   if (theAdvAnalyzer.IsNull()) return Standard_False;
   theAdvAnalyzer->CheckIntersectingEdges ( num, points2d, points3d, errors );
   if ( theAdvAnalyzer->LastCheckStatus ( ShapeExtend_FAIL ) ) {
@@ -2393,6 +2424,12 @@ Standard_Boolean ShapeFix_Wire::FixIntersectingEdges (const Standard_Integer num
   Standard_Integer n1 = ( n2  >1 ? n2-1 : sbwd->NbEdges() );
   TopoDS_Edge E1 = sbwd->Edge(n1);
   TopoDS_Edge E2 = sbwd->Edge(n2);
+  if ( !Context().IsNull() )
+  {
+    E1 = TopoDS::Edge(Context()->Apply(sbwd->Edge(n1))); 
+    E2 = TopoDS::Edge(Context()->Apply(sbwd->Edge(n2))); 
+  }
+
   Standard_Boolean isForward1 = ( E1.Orientation() == TopAbs_FORWARD );
   Standard_Boolean isForward2 = ( E2.Orientation() == TopAbs_FORWARD );
   Standard_Real a1, b1, a2, b2;
@@ -2411,6 +2448,7 @@ Standard_Boolean ShapeFix_Wire::FixIntersectingEdges (const Standard_Integer num
   Standard_Real prevRange1 = RealLast(), prevRange2 = RealLast();
   Standard_Boolean cutEdge1 = Standard_False, cutEdge2 = Standard_False;
   Standard_Boolean IsCutLine = Standard_False;
+  Standard_Boolean isChangedEdge = Standard_False;
 
   BRep_Builder B;
 
@@ -2453,6 +2491,8 @@ Standard_Boolean ShapeFix_Wire::FixIntersectingEdges (const Standard_Integer num
           // Make copy of edges.
           if (!Context().IsNull())
           {
+             isChangedEdge = Standard_True; // To avoid double copying of vertexes.
+
             // Intersection point of two base edges.
             ShapeBuild_Edge aSBE;
             TopoDS_Vertex VV1 = Context()->CopyVertex(V1);
@@ -2566,12 +2606,45 @@ Standard_Boolean ShapeFix_Wire::FixIntersectingEdges (const Standard_Integer num
 
   if ( ! LastFixStatus ( ShapeExtend_DONE ) ) return Standard_False;
 
-  B.UpdateVertex ( V1, pnt, tol );
-  B.UpdateVertex ( V2, pnt, tol );
+  if (isChangedEdge)
+  {
+    B.UpdateVertex ( V1, pnt, tol );
+    B.UpdateVertex ( V2, pnt, tol );
+  }
+  else
+  {
+    if ( !Context().IsNull() )
+    {
+      if (V1.IsSame(V2) )
+      {
+        Context()->CopyVertex(V1, pnt, tol);
+      }
+      else
+      {
+        Context()->CopyVertex(V1, pnt, tol);
+        Context()->CopyVertex(V2, pnt, tol);
+      }
+    }
+    else
+    {
+      B.UpdateVertex ( V1, pnt, tol );
+      B.UpdateVertex ( V2, pnt, tol );
+    }
+  }
 
   //:h4: make edges SP (after all cuts: t4mug.stp #3730+#6460)
-  if ( cutEdge1 ) myFixEdge->FixSameParameter ( E1 );
-  if ( cutEdge2 && !IsCutLine ) myFixEdge->FixSameParameter ( E2 );
+  if ( cutEdge1 ) 
+  {
+    if ( !Context().IsNull() )
+      E1 = TopoDS::Edge(Context()->Apply(E1));
+    myFixEdge->FixSameParameter ( E1 );
+  }
+  if ( cutEdge2 && !IsCutLine )
+  {
+    if ( !Context().IsNull() )
+      E2 = TopoDS::Edge(Context()->Apply(E2));
+    myFixEdge->FixSameParameter ( E2 );
+  }
   if ( cutEdge1 || cutEdge2 ) {
     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
   }
@@ -2595,7 +2668,7 @@ Standard_Boolean ShapeFix_Wire::FixIntersectingEdges (const Standard_Integer num
   IntRes2d_SequenceOfIntersectionPoint points2d;
   TColgp_SequenceOfPnt points3d;
   TColStd_SequenceOfReal errors;
-  Handle(ShapeAnalysis_Wire) theAdvAnalyzer = Handle(ShapeAnalysis_Wire)::DownCast(myAnalyzer);
+  Handle(ShapeAnalysis_Wire) theAdvAnalyzer = myAnalyzer;
   if (theAdvAnalyzer.IsNull()) return Standard_False;
   theAdvAnalyzer->CheckIntersectingEdges ( num1, num2, points2d, points3d, errors);
   if ( theAdvAnalyzer->LastCheckStatus ( ShapeExtend_FAIL ) ) {
@@ -2866,7 +2939,7 @@ Standard_Boolean ShapeFix_Wire::FixLacking (const Standard_Integer num,
   //=============
   // First phase: analysis whether the problem (gap) exists
   gp_Pnt2d p2d1, p2d2;
-  Handle(ShapeAnalysis_Wire)::DownCast(myAnalyzer)->CheckLacking ( num, ( force ? Precision() : 0. ), p2d1, p2d2 );
+  myAnalyzer->CheckLacking ( num, ( force ? Precision() : 0. ), p2d1, p2d2 );
   if ( myAnalyzer->LastCheckStatus ( ShapeExtend_FAIL ) ) {
     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
   }
@@ -3134,7 +3207,7 @@ Standard_Boolean ShapeFix_Wire::FixNotchedEdges()
   myLastFixStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
   if ( ! IsReady() ) return Standard_False;
   
-  Handle(ShapeAnalysis_Wire) theAdvAnalyzer = Handle(ShapeAnalysis_Wire)::DownCast(myAnalyzer);
+  Handle(ShapeAnalysis_Wire) theAdvAnalyzer = myAnalyzer;
   TopoDS_Face face = Face();
   if ( ! Context().IsNull() ) UpdateWire();
   Handle(ShapeExtend_WireData) sewd = WireData();