]> OCCT Git - occt.git/commitdiff
0033433: Shape Healing - Implement a new mode to keep initial types of curves. Some...
authorjfa <jfa@opencascade.com>
Wed, 25 Oct 2023 10:36:10 +0000 (11:36 +0100)
committerjfa <jfa@opencascade.com>
Wed, 25 Oct 2023 10:36:10 +0000 (11:36 +0100)
src/BRepTest/BRepTest_CurveCommands.cxx
src/ShapeFix/ShapeFix_Wire.cxx
src/ShapeFix/ShapeFix_Wire.hxx
src/ShapeFix/ShapeFix_Wire.lxx
tests/heal/wire_fix_curves/strongwire_circle
tests/heal/wire_fix_curves/strongwire_ellipse
tests/heal/wire_fix_curves/strongwire_halfcircle1
tests/heal/wire_fix_curves/strongwire_halfcircle2
tests/heal/wire_fix_curves/strongwire_nurb
tests/heal/wire_fix_curves/strongwire_triangle

index adf65e09c00565aaa6dd7f544cb6e989fa8999e9..3597d45da75c3798dc4838f3cc92a02e25922385 100644 (file)
@@ -283,7 +283,7 @@ static Standard_Integer wire(Draw_Interpretor& di, Standard_Integer n, const cha
 //=======================================================================
 // strongwire
 //=======================================================================
-static Standard_Integer strongwire(Draw_Interpretor& theDI, Standard_Integer theArgC, const char** theArgV)
+static Standard_Integer strongwire(Draw_Interpretor&, Standard_Integer theArgC, const char** theArgV)
 {
   enum StrongWireMode {
     StrongWireMode_FixTolerance = 1,
@@ -358,12 +358,12 @@ static Standard_Integer strongwire(Draw_Interpretor& theDI, Standard_Integer the
   aFW->Load(aWire);
   aFW->FixReorder();
 
-  if (aFW->StatusReorder(ShapeExtend_FAIL1)) 
+  if (aFW->StatusReorder(ShapeExtend_FAIL1))
   {
     Message::SendFail() << "Error: Wire construction failed: several loops detected";
     return 1;
   }
-  else if (aFW->StatusReorder(ShapeExtend_FAIL)) 
+  else if (aFW->StatusReorder(ShapeExtend_FAIL))
   {
     Message::SendFail() << "Wire construction failed";
     return 1;
@@ -371,7 +371,7 @@ static Standard_Integer strongwire(Draw_Interpretor& theDI, Standard_Integer the
 
   bool isClosed = false;
   Handle(ShapeAnalysis_Wire) aSaw = aFW->Analyzer();
-  if (aSaw->CheckGap3d(1)) // between last and first edges 
+  if (aSaw->CheckGap3d(1)) // between last and first edges
   {
     Standard_Real aDist = aSaw->MinDistance3d();
     if (aDist < aTolerance)
@@ -379,8 +379,6 @@ static Standard_Integer strongwire(Draw_Interpretor& theDI, Standard_Integer the
   }
   aFW->ClosedWireMode() = isClosed;
   aFW->FixConnected(aTolerance);
-  if (aMode == StrongWireMode_KeepCurveType)
-    aFW->FixCurves();
 
   if (aFW->StatusConnected(ShapeExtend_FAIL))
   {
@@ -388,16 +386,25 @@ static Standard_Integer strongwire(Draw_Interpretor& theDI, Standard_Integer the
     return 1;
   }
 
-  if (aFW->StatusConnected(ShapeExtend_DONE3)) 
+  if (aMode == StrongWireMode_KeepCurveType)
+  {
+    aFW->FixCurves();
+    if (aFW->StatusCurves(ShapeExtend_FAIL))
+    {
+      Message::SendFail() << "Wire construction failed: cannot rebuild curves through new points";
+      return 1;
+    }
+  }
+  else if (aFW->StatusConnected(ShapeExtend_DONE3))
   {
     if (aMode != StrongWireMode_Approximation)
-      aFW->SetPrecision(aTolerance); 
+      aFW->SetPrecision(aTolerance);
     aFW->FixGapsByRangesMode() = Standard_True;
     if (aFW->FixGaps3d())
     {
       Handle(ShapeExtend_WireData) sbwd = aFW->WireData();
       Handle(ShapeFix_Edge) aFe = new ShapeFix_Edge;
-      for (Standard_Integer anIdx = 1; anIdx <= sbwd->NbEdges(); anIdx++) 
+      for (Standard_Integer anIdx = 1; anIdx <= sbwd->NbEdges(); anIdx++)
       {
         TopoDS_Edge aEdge = TopoDS::Edge(sbwd->Edge(anIdx));
         aFe->FixVertexTolerance(aEdge);
index 82b6c36522c2d50fd70c795de79b40b088875c93..566456951b003dd39d770e0fd839aa7a065cdcca 100644 (file)
@@ -83,6 +83,7 @@
 #include <GeomAPI_ProjectPointOnCurve.hxx>
 #include <GeomAPI_ProjectPointOnSurf.hxx>
 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
+#include <gp_Elips.hxx>
 #include <gp_Pln.hxx>
 #include <IntRes2d_IntersectionPoint.hxx>
 #include <IntRes2d_SequenceOfIntersectionPoint.hxx>
@@ -248,6 +249,7 @@ void ShapeFix_Wire::ClearStatuses()
   myStatusReorder          = emptyStatus;
   myStatusSmall            = emptyStatus;
   myStatusConnected        = emptyStatus;
+  myStatusCurves           = emptyStatus;
   myStatusEdgeCurves       = emptyStatus;
   myStatusDegenerated      = emptyStatus;
   myStatusSelfIntersection = emptyStatus;
@@ -534,17 +536,15 @@ Standard_Boolean ShapeFix_Wire::FixConnected (const Standard_Real prec)
 //=======================================================================
 Standard_Boolean ShapeFix_Wire::FixCurves()
 {
-  myStatusConnected = ShapeExtend::EncodeStatus(ShapeExtend_OK);
+  myStatusCurves = ShapeExtend::EncodeStatus(ShapeExtend_OK);
   if (!IsLoaded()) return Standard_False;
 
-  Standard_Integer stop = (myClosedMode ? 0 : 1);
-  for (Standard_Integer anIdx = NbEdges(); anIdx > stop; anIdx--) 
-  {
+  for (Standard_Integer anIdx = NbEdges(); anIdx > 0; anIdx--) {
     FixCurves(anIdx);
-    myStatusConnected |= myLastFixStatus;
+    myStatusCurves |= myLastFixStatus;
   }
 
-  return StatusConnected(ShapeExtend_DONE);
+  return StatusCurves(ShapeExtend_DONE);
 }
 
 //=======================================================================
@@ -1366,14 +1366,12 @@ Standard_Boolean ShapeFix_Wire::FixCurves(const Standard_Integer theIdx)
   aCurve3d->D0(aCurBounds[0], aGeomEnds[0]);
   aCurve3d->D0(aCurBounds[2], aGeomEnds[1]);
 
-  // TODO: precise, if IsReversed flag should be considered here
   Standard_Real aGap0 = Min(anEnds[0].Distance(aGeomEnds[0]), anEnds[0].Distance(aGeomEnds[1]));
   Standard_Real aGap2 = Min(anEnds[2].Distance(aGeomEnds[0]), anEnds[2].Distance(aGeomEnds[1]));
-  if (Max (aGap0, aGap2) < aPrec) // nothing to do
+  if (Max (aGap0, aGap2) < Precision::Confusion()) // nothing to do
     return true;
 
-  if (aCurve3d->IsKind(STANDARD_TYPE(Geom_Circle))) 
-  {
+  if (aCurve3d->IsKind(STANDARD_TYPE(Geom_Circle))) {
     Standard_Real anOldR = Handle(Geom_Circle)::DownCast(aCurve3d)->Circ().Radius();
     gp_Vec anArcNorm = gp_Vec(anEnds[2], anEnds[0]) / 2;
     gp_Pnt aCenter(anEnds[0].XYZ() - anArcNorm.XYZ());
@@ -1390,15 +1388,20 @@ Standard_Boolean ShapeFix_Wire::FixCurves(const Standard_Integer theIdx)
     anSbwd->Set(aNewEdge, theIdx);
     return true;
   }
-  else if (aCurve3d->IsKind(STANDARD_TYPE(Geom_Ellipse)))
-  {
+  else if (aCurve3d->IsKind(STANDARD_TYPE(Geom_Ellipse))) {
+    /// aaajfa: BEGIN - to provide elliptic edge FORWARD orientation
+    gp_Pnt tmpPnt = anEnds[0];
+    anEnds[0] = anEnds[2];
+    anEnds[2] = tmpPnt;
+    /// aaajfa: END - to provide elliptic edge FORWARD orientation
+
     Handle(Geom_Ellipse) anOld = Handle(Geom_Ellipse)::DownCast(aCurve3d);
     Handle(Geom_Plane) aPln = new Geom_Plane(anEnds[0], gp_Vec(anEnds[2], anEnds[0]).Crossed(gp_Vec(anEnds[1], anEnds[0])));
     GeomAPI_ProjectPointOnSurf aProjector(anOld->Elips().Location(), aPln);
     gp_Pnt anOrigin = aProjector.NearestPoint();
     aProjector.Init(anOld->Elips().Location().XYZ() + anOld->Elips().XAxis().Direction().XYZ(), aPln);
     gp_Ax2 anAx(anOrigin, aPln->Axis().Direction(), aProjector.NearestPoint().XYZ() - anOrigin.XYZ());
-    
+
     // compute angle
     Standard_Real aRec = DBL_MAX;
     Standard_Real anAngle = 0.;
@@ -1406,7 +1409,8 @@ Standard_Boolean ShapeFix_Wire::FixCurves(const Standard_Integer theIdx)
     for (Standard_Integer anIdxI = -aSplNum; anIdxI < aSplNum; ++anIdxI)
     {
       Handle(Geom_Ellipse) anEll = new Geom_Ellipse(anAx, anOld->MajorRadius(), anOld->MinorRadius());
-      anEll->Rotate(anAx.Axis(), aPrec*anIdxI / anEll->MajorRadius() / aSplNum);
+      Standard_Real anAnglei = aPrec*anIdxI / anEll->MajorRadius() / aSplNum;
+      anEll->Rotate(anAx.Axis(), anAnglei);
       GeomAPI_ProjectPointOnCurve aProjector1(anEnds[0], anEll);
       Standard_Real aDist = 0.;
       for (Standard_Integer anIdxJ = 0; anIdxJ < 2; ++anIdxJ)
@@ -1417,7 +1421,7 @@ Standard_Boolean ShapeFix_Wire::FixCurves(const Standard_Integer theIdx)
       if (aDist < aRec)
       {
         aRec = aDist;
-        anAngle = aPrec*anIdxI / anEll->MajorRadius() / aSplNum;
+        anAngle = anAnglei;
       }
     }
     gp_Elips aTemp(anAx, anOld->MajorRadius(), anOld->MinorRadius());
@@ -1428,7 +1432,7 @@ Standard_Boolean ShapeFix_Wire::FixCurves(const Standard_Integer theIdx)
     gp_Vec aY = aTemp.YAxis().Direction();
     gp_Pnt2d aP1((anEnds[0].XYZ() - anOrigin.XYZ()).Dot(aX.XYZ()), (anEnds[0].XYZ() - anOrigin.XYZ()).Dot(aY.XYZ()));
     gp_Pnt2d aP2((anEnds[2].XYZ() - anOrigin.XYZ()).Dot(aX.XYZ()), (anEnds[2].XYZ() - anOrigin.XYZ()).Dot(aY.XYZ()));
-    
+
     // x = ky + p   linear equation
     // where (x, y) shift point, 
     // k, p constant coefficients
@@ -1452,14 +1456,14 @@ Standard_Boolean ShapeFix_Wire::FixCurves(const Standard_Integer theIdx)
     Standard_Real y2 = (-b + sqrt(b*b - 4 * a*c)) / 2 / a;
     Standard_Real x1 = k*y1 + p;
     Standard_Real x2 = k*y2 + p;
-    
+
     gp_Pnt anOri = anOld->Location();
     if (x1*x1 + y1*y1 < x2*x2 + y2*y2) 
       anOri = anOri.XYZ() + aX.XYZ()*x1 + aY.XYZ()*y1;
     else
       anOri = anOri.XYZ() + aX.XYZ()*x2 + aY.XYZ()*y2;
     aTemp.SetLocation(anOri);
-    
+
     GC_MakeArcOfEllipse anArc(aTemp, anEnds[2], anEnds[0], true);
     TopoDS_Edge aNewEdge = BRepBuilderAPI_MakeEdge(anArc.Value()).Edge();
     anSbwd->Set(aNewEdge, theIdx);
@@ -1467,7 +1471,7 @@ Standard_Boolean ShapeFix_Wire::FixCurves(const Standard_Integer theIdx)
   }
   else if (aCurve3d->IsKind(STANDARD_TYPE(Geom_Line)))
   {
-    TopoDS_Edge aNewEdge = BRepBuilderAPI_MakeEdge(anEnds[2], anEnds[0]).Edge();
+    TopoDS_Edge aNewEdge = BRepBuilderAPI_MakeEdge(anEnds[0], anEnds[2]).Edge();
     anSbwd->Set(aNewEdge, theIdx);
     return true;
   }
@@ -1489,12 +1493,6 @@ Standard_Boolean ShapeFix_Wire::FixCurves(const Standard_Integer theIdx)
     return true;
   }
 
-  // TODO: question: the below code works only for other curve types (not line/arc/circle/ellipse/bspline)
-  //                 Is it really needed?
-  myAnalyzer->CheckConnected(theIdx, aPrec);
-  if (myAnalyzer->LastCheckStatus(ShapeExtend_FAIL))
-    myLastFixStatus |= ShapeExtend::EncodeStatus(ShapeExtend_FAIL1);
-
   return true;
 }
 
index 660e2a1d94d10c989d705d48f0e179af25b7def0..6e74c9be2cfe78d1ba19ff74ca6baba868d555d7 100644 (file)
@@ -416,6 +416,8 @@ public:
   
     Standard_Boolean StatusConnected (const ShapeExtend_Status status) const;
   
+    Standard_Boolean StatusCurves (const ShapeExtend_Status status) const;
+  
     Standard_Boolean StatusEdgeCurves (const ShapeExtend_Status status) const;
   
     Standard_Boolean StatusDegenerated (const ShapeExtend_Status status) const;
@@ -501,6 +503,7 @@ protected:
   Standard_Integer myStatusReorder;
   Standard_Integer myStatusSmall;
   Standard_Integer myStatusConnected;
+  Standard_Integer myStatusCurves;
   Standard_Integer myStatusEdgeCurves;
   Standard_Integer myStatusDegenerated;
   Standard_Integer myStatusClosed;
index 2ba6455f1ccb3128db2976a9faa9468be510a308..ef70ca7f2b66e85fd9f116aef36006051b499161 100644 (file)
@@ -447,6 +447,16 @@ inline  Standard_Boolean ShapeFix_Wire::StatusConnected(const ShapeExtend_Status
   return ShapeExtend::DecodeStatus ( myStatusConnected, status ); 
 }
 
+//=======================================================================
+//function : StatusCurves
+//purpose  : 
+//=======================================================================
+
+inline  Standard_Boolean ShapeFix_Wire::StatusCurves(const ShapeExtend_Status status) const
+{
+  return ShapeExtend::DecodeStatus ( myStatusCurves, status ); 
+}
+
 //=======================================================================
 //function : StatusEdgeCurves
 //purpose  : 
index 6e75aca9daee27b5b7f69efed58c908ca691d514..5796a4e895e439d618208398cf8f3fe204a97759 100644 (file)
@@ -11,6 +11,6 @@ translate c1 0 0 0.00000005
 translate c2 0 0 -0.00000005
 mkedge c1 c1
 mkedge c2 c2
-strongwire w c1 c2
-checkshape w
-whatis w
+strongwire result c1 c2
+checkshape result
+whatis result
index 558fe23bbc087bcae546e3ae8f69eb5e963faf9a..6d7a545bc0b755aebfa1ba51695f259fb08cb9c5 100644 (file)
@@ -11,6 +11,6 @@ translate e1 0 0 0.00000005
 translate e2 0 0 -0.00000005
 mkedge e1 e1
 mkedge e2 e2
-strongwire w e1 e2 
-checkshape w
-whatis w
+strongwire result e1 e2
+checkshape result
+whatis result
index e0017b3889b247b7df074140603f9661de60ea42..a72bd48d3731d7e845dbd096789793d52993da3e 100644 (file)
@@ -11,8 +11,14 @@ vertex vx px
 vertex vy py
 
 edge exy vx vy
+
 gcarc arc cir py pz px
+
+# Here we have an error during automatic grid execution with test and testgrid:
+# Tcl Exception: EMPTY
+# But in line-by-line entering or script sourcing mode this line doesn't produce any error
+
 mkedge earc arc
 
-strongwire w exy earc
-whatis w
\ No newline at end of file
+strongwire result exy earc
+whatis result
index b873196424fc0cc259fc626579e465fec3e2af57..005fd5fc6097196159b486693901dfc3d98fa0ab 100644 (file)
@@ -7,9 +7,11 @@ point p1   0   0  0
 point p2 100   0  0
 point p4 100 110  0
 
-
 gcarc arc cir p1 p2 p4
 
+# Here we have an error during automatic grid execution with test and testgrid:
+# Tcl Exception: EMPTY
+# But in line-by-line entering or script sourcing mode this line doesn't produce any error
 
 mkedge arc1 arc
 mkedge arc2 arc
@@ -17,7 +19,7 @@ mkedge arc2 arc
 tmirror arc2 0 0 0 -110 100 0 -copy
 ttranslate arc2 0 0 0.003 -copy
 
-strongwire w1 arc1 arc2 -t 0.01 -m keepType
+strongwire result arc1 arc2 -t 0.01 -m keepType
 
-checkshape w1
-whatis w1
\ No newline at end of file
+checkshape result
+whatis result
index d65cd2d33601df778eb21b677aff7874ff05dbd0..b32c5c1bdc526a199696d1f977674e3a6d564425 100644 (file)
@@ -9,6 +9,6 @@ translate c1 0 0 0.00000005
 translate c2 0 0 -0.00000005
 mkedge c1 c1
 mkedge c2 c2
-strongwire w c1 c2
-checkshape w
-whatis w
\ No newline at end of file
+strongwire result c1 c2
+checkshape result
+whatis result
index 433c6edcadd3f63ed31340748c42f91848af58b7..0ad5246ddce80198e1d0e82f96fa4cd63afa494c 100644 (file)
@@ -11,7 +11,7 @@ edge e1 v1 v2
 edge e2 v2 v3
 edge e3 v3 v1
 
-strongwire w1 e1 e2 e3
+strongwire result e1 e2 e3
 
-checkshape w1
-whatis w1
+checkshape result
+whatis result