0026261: Create a tool to remove tails from any wire
authorabk <abk@opencascade.com>
Tue, 19 May 2015 17:03:11 +0000 (20:03 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 28 May 2015 12:18:44 +0000 (15:18 +0300)
A tool to remove tails from the wires of a shape was created.
The tool is based on mechanism 'ShapeFix',
is located in types 'ShapeFix_Wire' and 'ShapeAnalysis_Wire',
is enabled through method 'ShapeFix_Wire::FixTailMode' and
is initialized by methods 'ShapeFix_Wire::SetMaxTailAngle' and 'ShapeFix_Wire::SetMaxTailWidth' and
is called through method 'ShapeFix_Wire::FixTails'.
The status of any performing of the last method is accessible through method 'ShapeFix_Wire::StatusFixTails'.
The tail angle is checked only at the tail start.

Mechanism 'ShapeFix' was modified:
- the tool is disabled by default;
- algorithm 'Fix notched edges' is disabled then the tool is enabled;
- the tool and the last algorithm work in turns then the tool works on the request.

'Draw' command 'fixshape' was extended by options '-maxtaila' and '-maxtailw' to test the tool.

'Draw' tests to test the tool were created.

Algorithm 'fixshape' was changed in type 'ShapeProcess_OperLibrary' to
- use new parameters named 'FixTailMode', 'MaxTailAngle' (in degrees) and 'MaxTailWidth' from the algorithm context;
- apply the tool after the shape will be fully fixed if the tool was enabled.

Place holders for the new parameters were created in the resource file of mechsnism 'STEPControl_Reader'.

Test cases for issue CR26261

38 files changed:
src/SWDRAW/SWDRAW_ShapeFix.cxx
src/ShapeAnalysis/ShapeAnalysis_Wire.cdl
src/ShapeAnalysis/ShapeAnalysis_Wire.cxx
src/ShapeFix/ShapeFix_Face.cxx
src/ShapeFix/ShapeFix_Wire.cdl
src/ShapeFix/ShapeFix_Wire.cxx
src/ShapeFix/ShapeFix_Wire.lxx
src/ShapeProcess/ShapeProcess_OperLibrary.cxx
src/XSTEPResource/STEP
tests/heal/begin
tests/heal/end
tests/heal/grids.list
tests/heal/wire_tails_composed/A1 [new file with mode: 0644]
tests/heal/wire_tails_composed/A10 [new file with mode: 0644]
tests/heal/wire_tails_composed/A11 [new file with mode: 0644]
tests/heal/wire_tails_composed/A12 [new file with mode: 0644]
tests/heal/wire_tails_composed/A13 [new file with mode: 0644]
tests/heal/wire_tails_composed/A14 [new file with mode: 0644]
tests/heal/wire_tails_composed/A15 [new file with mode: 0644]
tests/heal/wire_tails_composed/A16 [new file with mode: 0644]
tests/heal/wire_tails_composed/A17 [new file with mode: 0644]
tests/heal/wire_tails_composed/A18 [new file with mode: 0644]
tests/heal/wire_tails_composed/A19 [new file with mode: 0644]
tests/heal/wire_tails_composed/A2 [new file with mode: 0644]
tests/heal/wire_tails_composed/A3 [new file with mode: 0644]
tests/heal/wire_tails_composed/A4 [new file with mode: 0644]
tests/heal/wire_tails_composed/A5 [new file with mode: 0644]
tests/heal/wire_tails_composed/A6 [new file with mode: 0644]
tests/heal/wire_tails_composed/A7 [new file with mode: 0644]
tests/heal/wire_tails_composed/A8 [new file with mode: 0644]
tests/heal/wire_tails_composed/A9 [new file with mode: 0644]
tests/heal/wire_tails_real/A1 [new file with mode: 0644]
tests/heal/wire_tails_real/A2 [new file with mode: 0644]
tests/heal/wire_tails_real/A3 [new file with mode: 0644]
tests/heal/wire_tails_real/A4 [new file with mode: 0644]
tests/heal/wire_tails_real/A5 [new file with mode: 0644]
tests/heal/wire_tails_real/A6 [new file with mode: 0644]
tests/heal/wire_tails_real/A7 [new file with mode: 0644]

index de47ca3..7bfd3c4 100644 (file)
@@ -413,8 +413,11 @@ static Standard_Integer fixshape (Draw_Interpretor& di, Standard_Integer argc, c
   
   Standard_CString res = 0;
   Standard_Integer par = 0, mess=0;
-  for ( Standard_Integer i=1; i < argc; i++ ) {
-    if ( argv[i][0] == '-' || argv[i][0] == '+' || argv[i][0] == '*' ) {
+  for ( Standard_Integer i=1; i < argc; i++ )
+  {
+    if (strlen(argv[i]) == 2 &&
+      (argv[i][0] == '-' || argv[i][0] == '+' || argv[i][0] == '*'))
+    {
       Standard_Integer val = ( argv[i][0] == '-' ? 0 : argv[i][0] == '+' ? 1 : -1 );
       switch ( argv[i][1] ) {
       case 'l': sfs->FixWireTool()->FixLackingMode()          = val; break;
@@ -429,7 +432,27 @@ static Standard_Integer fixshape (Draw_Interpretor& di, Standard_Integer argc, c
       }
       continue;
     }
-    else {
+    else if (!strcmp(argv[i], "-maxtaila"))
+    {
+      if (++i >= argc)
+      {
+        break;
+      }
+
+      sfs->FixWireTool()->SetMaxTailAngle(Draw::Atof(argv[i]) * (M_PI / 180));
+    }
+    else if (!strcmp(argv[i], "-maxtailw"))
+    {
+      if (++i >= argc)
+      {
+        break;
+      }
+
+      sfs->FixWireTool()->SetMaxTailWidth(Draw::Atof(argv[i]));
+      sfs->FixWireTool()->FixTailMode() = 1;
+    }
+    else
+    {
       switch ( par ) {
       case 0: res = argv[i];                       break;
       case 1: {
@@ -445,7 +468,8 @@ static Standard_Integer fixshape (Draw_Interpretor& di, Standard_Integer argc, c
   }
 
   if ( par <2 ) {
-    di << "Use: " << argv[0] << " result shape [tolerance [max_tolerance]] [switches]" << "\n"; 
+    di << "Use: " << argv[0] << " result shape [tolerance [max_tolerance]] [switches]\n"
+      "[-maxtaila <degrees>] [-maxtailw <width>]" << "\n";
     di << "Switches allow to tune parameters of ShapeFix" << "\n"; 
     di << "The following syntax is used: <symbol><parameter>" << "\n"; 
     di << "- symbol may be - to set parameter off, + to set on or * to set default" << "\n"; 
@@ -787,7 +811,9 @@ static Standard_Integer connectedges(Draw_Interpretor& di, Standard_Integer n, c
                   __FILE__,stwire,g);
   theCommands.Add ("reface","shape result : controle sens wire",
                   __FILE__,reface,g);
-  theCommands.Add ("fixshape","res shape [preci [maxpreci]] [{switches}]",
+  theCommands.Add ("fixshape",
+"res shape [preci [maxpreci]] [{switches}]\n"
+"  [-maxtaila <degrees>] [-maxtailw <width>]",
                   __FILE__,fixshape,g);
 //  theCommands.Add ("testfill","result edge1 edge2",
 //                __FILE__,XSHAPE_testfill,g);
index 572dc4a..2083428 100644 (file)
@@ -64,6 +64,7 @@ uses
     Shape     from TopoDS,
     Wire      from TopoDS,
     Face      from TopoDS,
+    Edge      from TopoDS,
     SequenceOfIntersectionPoint from IntRes2d,
     SequenceOfPnt               from TColgp,
     SequenceOfReal              from TColStd,
@@ -545,6 +546,17 @@ is
                             aMapSeemEdges : out MapOfShape from TopTools) returns Boolean;
        ---Purpose: Checks existance of loop on wire and return vertices wich are loop vertices 
 -- (vertices belonging to a few pairs of edges)
+
+    CheckTail(me : mutable;
+      theEdge1: in Edge from TopoDS;
+      theEdge2: in Edge from TopoDS;
+      theMaxSine: in Real;
+      theMaxWidth: in Real;
+      theMaxTolerance: in Real;
+      theEdge11: out Edge from TopoDS;
+      theEdge12: out Edge from TopoDS;
+      theEdge21: out Edge from TopoDS;
+      theEdge22: out Edge from TopoDS) returns Boolean;
        
        
        ---Status after checking :
index 264639c..1c0406d 100644 (file)
 #include <Bnd_Box2d.hxx>
 
 //szvsh addition
+#include <BRepGProp.hxx>
+#include <GCPnts_AbscissaPoint.hxx>
 #include <Geom2dAdaptor_HCurve.hxx>
+#include <GeomAdaptor_Curve.hxx>
+#include <GProp_GProps.hxx>
 #include <Adaptor3d_CurveOnSurface.hxx>
 #include <TColgp_SequenceOfPnt.hxx>
 #include <ShapeAnalysis_Surface.hxx>
 #include <TopoDS_Wire.hxx>
 #include <ShapeAnalysis.hxx>
+#include <ShapeAnalysis_TransferParametersProj.hxx>
+#include <ShapeBuild_Edge.hxx>
 #include <Geom_Plane.hxx>
 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
 #include <TopoDS_Iterator.hxx>
@@ -1964,3 +1970,283 @@ Standard_Boolean isMultiVertex(const TopTools_ListOfShape& alshape,
   }
   return Standard_False;
 }
+
+//=======================================================================
+//function : Project
+//purpose  :
+//=======================================================================
+static Standard_Real Project(
+  const Handle(Geom_Curve)& theCurve,
+  const Standard_Real theFirstParameter,
+  const Standard_Real theLastParameter,
+  const gp_Pnt& thePoint,
+  const Standard_Real thePrecision,
+  Standard_Real& theParameter,
+  gp_Pnt& theProjection)
+{
+  const Standard_Real aDist = ShapeAnalysis_Curve().Project(theCurve, thePoint,
+    thePrecision, theProjection, theParameter, theFirstParameter,
+    theLastParameter);
+  if (theParameter >= theFirstParameter && theParameter <= theLastParameter)
+  {
+    return aDist;
+  }
+
+  const Standard_Real aParams[] = {theFirstParameter, theLastParameter};
+  const gp_Pnt aPrjs[] =
+    {theCurve->Value(aParams[0]), theCurve->Value(aParams[1])};
+  const Standard_Real aDists[] =
+    {thePoint.Distance(aPrjs[0]), thePoint.Distance(aPrjs[1])};
+  const Standard_Integer aPI = (aDists[0] <= aDists[1]) ? 0 : 1;
+  theParameter = aParams[aPI];
+  theProjection = aPrjs[aPI];
+  return aDists[aPI];
+}
+
+//=======================================================================
+//function : CheckTail
+//purpose  :
+//=======================================================================
+Standard_Boolean ShapeAnalysis_Wire::CheckTail(
+  const TopoDS_Edge& theEdge1,
+  const TopoDS_Edge& theEdge2,
+  const Standard_Real theMaxSine,
+  const Standard_Real theMaxWidth,
+  const Standard_Real theMaxTolerance,
+  TopoDS_Edge& theEdge11,
+  TopoDS_Edge& theEdge12,
+  TopoDS_Edge& theEdge21,
+  TopoDS_Edge& theEdge22)
+{
+  const TopoDS_Edge aEs[] = {theEdge1, theEdge2};
+  if (!IsReady() || BRep_Tool::Degenerated(aEs[0]) ||
+    BRep_Tool::Degenerated(aEs[1]))
+  {
+    return Standard_False;
+  }
+
+  // Check the distance between the edge common ends.
+  const Standard_Real aTol2 = theMaxWidth + 0.5 * Precision::Confusion();
+  const Standard_Real aTol3 = theMaxWidth + Precision::Confusion();
+  const Standard_Real aTol4 = theMaxWidth + 1.5 * Precision::Confusion();
+  const Standard_Real aSqTol2 = aTol2 * aTol2;
+  const Standard_Real aSqTol3 = aTol3 * aTol3;
+  Handle(Geom_Curve) aCs[2];
+  Standard_Real aLs[2][2];
+  Standard_Integer aVIs[2];
+  gp_Pnt aVPs[2];
+  {
+    for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
+    {
+      if (!ShapeAnalysis_Edge().Curve3d(
+        aEs[aEI], aCs[aEI], aLs[aEI][0], aLs[aEI][1], Standard_False))
+      {
+        return Standard_False;
+      }
+
+      aVIs[aEI] = (aEs[aEI].Orientation() == TopAbs_REVERSED) ? aEI : 1 - aEI;
+      aVPs[aEI] = aCs[aEI]->Value(aLs[aEI][aVIs[aEI]]);
+    }
+    if (aVPs[0].SquareDistance(aVPs[1]) > aSqTol2)
+    {
+      return Standard_False;
+    }
+  }
+
+  // Check the angle between the edges.
+  if (theMaxSine >= 0)
+  {
+    const Standard_Real aSqMaxSine = theMaxSine * theMaxSine;
+    gp_XYZ aDs[2];
+    Standard_Integer aReverse = 0;
+    for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
+    {
+      GeomAdaptor_Curve aCA(aCs[aEI]);
+      if (GCPnts_AbscissaPoint::Length(aCA, aLs[aEI][0], aLs[aEI][1],
+        0.25 * Precision::Confusion()) < 0.5 * Precision::Confusion())
+      {
+        return Standard_False;
+      }
+
+      GCPnts_AbscissaPoint aAP(0.25 * Precision::Confusion(), aCA,
+        0.5 * Precision::Confusion() * (1 - 2 * aVIs[aEI]),
+        aLs[aEI][aVIs[aEI]]);
+      if (!aAP.IsDone())
+      {
+        return Standard_False;
+      }
+
+      gp_XYZ aPs[2];
+      aPs[aVIs[aEI]] = aVPs[aEI].XYZ();
+      aPs[1 - aVIs[aEI]] = aCs[aEI]->Value(aAP.Parameter()).XYZ();
+      aDs[aEI] = aPs[1] - aPs[0];
+      const Standard_Real aDN = aDs[aEI].Modulus();
+      if (aDN < 0.1 * Precision::Confusion())
+      {
+        return Standard_False;
+      }
+
+      aDs[aEI] *= 1 / aDN;
+      aReverse ^= aVIs[aEI];
+    }
+    if (aReverse)
+    {
+      aDs[0].Reverse();
+    }
+    if (aDs[0] * aDs[1] < 0 || aDs[0].CrossSquareMagnitude(aDs[1]) > aSqMaxSine)
+    {
+      return Standard_False;
+    }
+  }
+
+  // Calculate the tail bounds.
+  gp_Pnt aPs[2], aPrjs[2];
+  Standard_Real aParams1[2], aParams2[2];
+  Standard_Real aDists[2];
+  Standard_Boolean isWholes[] = {Standard_True, Standard_True};
+  for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
+  {
+    Standard_Real aParam1 = aLs[aEI][aVIs[aEI]];
+    aParams1[aEI] = aLs[aEI][1 - aVIs[aEI]];
+    aCs[aEI]->D0(aParams1[aEI], aPs[aEI]);
+    aDists[aEI] = Project(aCs[1 - aEI], aLs[1 - aEI][0], aLs[1 - aEI][1],
+      aPs[aEI], 0.25 * Precision::Confusion(), aParams2[aEI], aPrjs[aEI]);
+    if (aDists[aEI] <= aTol2)
+    {
+      continue;
+    }
+
+    isWholes[aEI] = Standard_False;
+    for (;;)
+    {
+      const Standard_Real aParam = (aParam1 + aParams1[aEI]) * 0.5;
+      aCs[aEI]->D0(aParam, aPs[aEI]);
+      const Standard_Real aDist = Project(aCs[1 - aEI], aLs[1 - aEI][0],
+        aLs[1 - aEI][1], aPs[aEI], 0.25 * Precision::Confusion(), aParams2[aEI],
+        aPrjs[aEI]);
+      if (aDist <= aTol2)
+      {
+        aParam1 = aParam;
+      }
+      else
+      {
+        aParams1[aEI] = aParam;
+        if (aDist <= aTol3)
+        {
+          break;
+        }
+      }
+    }
+  }
+
+  // Check the tail bounds.
+  for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
+  {
+    const Standard_Real aParam1 = aLs[aEI][aVIs[aEI]];
+    const Standard_Real aParam2 = aParams1[aEI];
+    const Standard_Real aStepL = (aParam2 - aParam1) / 23;
+    for (Standard_Integer aStepN = 1; aStepN < 23; ++aStepN)
+    {
+      Standard_Real aParam = aParam1 + aStepN * aStepL;
+      gp_Pnt aP = aCs[aEI]->Value(aParam), aPrj;
+      if (Project(aCs[1 - aEI], aLs[1 - aEI][0], aLs[1 - aEI][1], aP,
+        0.25 * Precision::Confusion(), aParam, aPrj) > aTol4)
+      {
+        return Standard_False;
+      }
+    }
+  }
+
+  // Check whether both edges must be removed.
+  if (isWholes[0] && isWholes[1] && aPs[0].SquareDistance(aPs[1]) <= aSqTol3)
+  {
+    theEdge11 = theEdge1;
+    theEdge21 = theEdge2;
+    return Standard_True;
+  }
+
+  // Cut and remove the edges.
+  Standard_Integer aFI = 0;
+  if (isWholes[0] || isWholes[1])
+  {
+    // Determine an edge to remove and the other one to cut.
+    aFI = isWholes[0] ? 0 : 1;
+    if (aDists[1 - aFI] < aDists[aFI] && isWholes[1 - aFI])
+    {
+      aFI = 1 - aFI;
+    }
+  }
+  Standard_Real aParams[2];
+  aParams[aFI] = aParams1[aFI];
+  aParams[1 - aFI] = aParams2[aFI];
+
+  // Correct the cut for the parametrization tolerance.
+  TopoDS_Edge* aEParts[][2] =
+    {{&theEdge11, &theEdge12}, {&theEdge21, &theEdge22}};
+  Standard_Integer aResults[] = {1, 1};
+  for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
+  {
+    if (Abs(aParams[aEI] - aLs[aEI][1 - aVIs[aEI]]) <= Precision::PConfusion())
+    {
+      aResults[aEI] = 2;
+      *aEParts[aEI][0] = aEs[aEI];
+    }
+    else if (Abs(aParams[aEI] - aLs[aEI][aVIs[aEI]]) <= Precision::PConfusion())
+    {
+      aResults[aEI] = 0;
+    }
+  }
+
+  // Correct the cut for the distance tolerance.
+  for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
+  {
+    if (aResults[aEI] != 1)
+    {
+      continue;
+    }
+
+    // Create the parts of the edge.
+    TopoDS_Edge aFE = TopoDS::Edge(aEs[aEI].Oriented(TopAbs_FORWARD));
+    ShapeAnalysis_TransferParametersProj aSATPP(aFE, TopoDS_Face());
+    aSATPP.SetMaxTolerance(theMaxTolerance);
+    TopoDS_Vertex aSplitV;
+    BRep_Builder().MakeVertex(
+      aSplitV, aCs[aEI]->Value(aParams[aEI]), Precision::Confusion());
+    TopoDS_Edge aEParts2[] = {
+      ShapeBuild_Edge().CopyReplaceVertices(aFE, TopoDS_Vertex(),
+        TopoDS::Vertex(aSplitV.Oriented(TopAbs_REVERSED))),
+      ShapeBuild_Edge().CopyReplaceVertices(aFE, aSplitV, TopoDS_Vertex())};
+    ShapeBuild_Edge().CopyPCurves(aEParts2[0], aFE);
+    ShapeBuild_Edge().CopyPCurves(aEParts2[1], aFE);
+    BRep_Builder().SameRange(aEParts2[0], Standard_False);
+    BRep_Builder().SameRange(aEParts2[1], Standard_False);
+    BRep_Builder().SameParameter(aEParts2[0], Standard_False);
+    BRep_Builder().SameParameter(aEParts2[1], Standard_False);
+    aSATPP.TransferRange(
+      aEParts2[0], aLs[aEI][0], aParams[aEI], Standard_False);
+    aSATPP.TransferRange(
+      aEParts2[1], aParams[aEI], aLs[aEI][1], Standard_False);
+    GProp_GProps aLinProps;
+    BRepGProp::LinearProperties(aEParts2[1 - aVIs[aEI]], aLinProps);
+    if (aLinProps.Mass() <= Precision::Confusion())
+    {
+      aResults[aEI] = 2;
+      *aEParts[aEI][0] = aEs[aEI];
+    }
+    else
+    {
+      BRepGProp::LinearProperties(aEParts2[aVIs[aEI]], aLinProps);
+      if (aLinProps.Mass() <= Precision::Confusion())
+      {
+        aResults[aEI] = 0;
+      }
+      else
+      {
+        *aEParts[aEI][0] = aEParts2[0];
+        *aEParts[aEI][1] = aEParts2[1];
+      }
+    }
+  }
+
+  return aResults[0] + aResults[1] != 0;
+}
index acce19f..ba90f6d 100644 (file)
@@ -462,6 +462,7 @@ Standard_Boolean ShapeFix_Face::Perform()
                theAdvFixWire->StatusConnected(ShapeExtend_DONE) ||
                theAdvFixWire->StatusEdgeCurves(ShapeExtend_DONE) ||
                theAdvFixWire->StatusNotches(ShapeExtend_DONE) ||  // CR0024983
+               theAdvFixWire->StatusFixTails(ShapeExtend_DONE) ||
                theAdvFixWire->StatusDegenerated(ShapeExtend_DONE) ||
                theAdvFixWire->StatusClosed(ShapeExtend_DONE));
         TopoDS_Wire w = theAdvFixWire->Wire();
@@ -561,9 +562,10 @@ Standard_Boolean ShapeFix_Face::Perform()
         }
        if ( theAdvFixWire->Perform() ) {
           isfixReorder =  theAdvFixWire->StatusReorder(ShapeExtend_DONE);
-         fixed = (theAdvFixWire->StatusLacking(ShapeExtend_DONE) ||
-                   theAdvFixWire->StatusSelfIntersection(ShapeExtend_DONE) ||
-                   theAdvFixWire->StatusNotches(ShapeExtend_DONE));  //Standard_True; 
+          fixed = (theAdvFixWire->StatusLacking(ShapeExtend_DONE) ||
+            theAdvFixWire->StatusSelfIntersection(ShapeExtend_DONE) ||
+            theAdvFixWire->StatusNotches(ShapeExtend_DONE) ||
+            theAdvFixWire->StatusFixTails(ShapeExtend_DONE));
          TopoDS_Wire w = theAdvFixWire->Wire();
           if(fixed) {
             if ( ! Context().IsNull() ) Context()->Replace ( wire, w );
index a5a63a5..75f1f1b 100644 (file)
@@ -59,8 +59,10 @@ class Wire from ShapeFix inherits Root from ShapeFix
     --          a) Wire (ether TopoDS_Wire or ShapeExtend_Wire)
     --          b) Face or surface
     --          c) Precision
+    --          d) Maximal tail angle and width
     --          This can be done either by calling corresponding methods
-    --          (LoadWire, SetFace or SetSurface, and SetPrecision), or
+    --          (LoadWire, SetFace or SetSurface, SetPrecision, SetMaxTailAngle
+    --          and SetMaxTailWidth), or
     --          by loading already filled ShapeAnalisis_Wire with method Load
 
 uses 
@@ -131,6 +133,12 @@ is
     SetPrecision (me: mutable; prec: Real) is redefined;
        ---Purpose: Set working precision (to root and to analyzer)
 
+    SetMaxTailAngle (me: mutable; theMaxTailAngle: Real);
+      ---Purpose: Sets the maximal allowed angle of the tails in radians.
+
+    SetMaxTailWidth (me: mutable; theMaxTailWidth: Real);
+      ---Purpose: Sets the maximal allowed width of the tails.
+
     IsLoaded (me) returns Boolean;
        ---C++: inline
        ---Purpose: Tells if the wire is loaded 
@@ -313,6 +321,9 @@ is
        --       -1 default
        --        1 method will be called
        --        0 method will not be called
+    FixTailMode(me: mutable) returns Integer;
+      ---C++: inline
+      ---C++: return &
 
     --- Fixing methods:
     
@@ -767,6 +778,8 @@ is
        --          FAIL1 - There was no pcurve found on some edge
        --          FAIL2 - Method failed to fix the gap
 
+    FixTails(me: mutable) returns Boolean;
+
     --- Result of fixes: 
 
     StatusReorder          (me; status: Status from ShapeExtend) returns Boolean;
@@ -800,6 +813,9 @@ is
        --          DONE: some problem(s) was(were) detected and successfully fixed
        --          FAIL: some problem(s) cannot be fixed
        ---Level  : Public (API)
+    StatusFixTails(me; status: Status from ShapeExtend) returns Boolean;
+      ---C++: inline
+
     LastFixStatus (me; status: Status from ShapeExtend) returns Boolean;                
        ---C++: inline
        ---Purpose: Queries the status of last call to methods Fix... of 
@@ -843,6 +859,7 @@ fields
     myFixSelfIntersectingEdgeMode:          Integer is protected;
     myFixIntersectingEdgesMode:             Integer is protected;
     myFixNonAdjacentIntersectingEdgesMode:  Integer is protected;
+    myFixTailMode:                          Integer is protected;
 
     myRemoveLoopMode:                       Integer is protected;
       -- -1 - old variant (default)
@@ -874,4 +891,7 @@ fields
     myStatusGaps2d:           Integer is protected;
     myStatusRemovedSegment:   Boolean is protected;
     myStatusNotches:          Integer is protected;
+    myStatusFixTails:         Integer is protected;
+    myMaxTailAngleSine:       Real is protected;
+    myMaxTailWidth:           Real is protected;
 end Wire;
index f3f05d6..2505f0e 100644 (file)
 //purpose  : 
 //=======================================================================
 
-ShapeFix_Wire::ShapeFix_Wire()
+ShapeFix_Wire::ShapeFix_Wire() : myMaxTailAngleSine(0), myMaxTailWidth(-1)
 {
   myFixEdge = new ShapeFix_Edge;
   myAnalyzer = new ShapeAnalysis_Wire;
@@ -143,8 +143,10 @@ ShapeFix_Wire::ShapeFix_Wire()
 //purpose  : 
 //=======================================================================
 
-ShapeFix_Wire::ShapeFix_Wire (const TopoDS_Wire& wire, 
-                             const TopoDS_Face &face, const Standard_Real prec)
+ShapeFix_Wire::ShapeFix_Wire (
+  const TopoDS_Wire& wire,
+  const TopoDS_Face &face,
+  const Standard_Real prec) : myMaxTailAngleSine(0), myMaxTailWidth(-1)
 {
   myFixEdge = new ShapeFix_Edge;
   myAnalyzer = new ShapeAnalysis_Wire;
@@ -166,6 +168,25 @@ void ShapeFix_Wire::SetPrecision (const Standard_Real prec)
 }
  
 //=======================================================================
+//function : SetMaxTailAngle
+//purpose  :
+//=======================================================================
+void ShapeFix_Wire::SetMaxTailAngle(const Standard_Real theMaxTailAngle)
+{
+  myMaxTailAngleSine = Sin(theMaxTailAngle);
+  myMaxTailAngleSine = (myMaxTailAngleSine >= 0) ? myMaxTailAngleSine : 0;
+}
+
+//=======================================================================
+//function : SetMaxTailWidth
+//purpose  :
+//=======================================================================
+void ShapeFix_Wire::SetMaxTailWidth(const Standard_Real theMaxTailWidth)
+{
+  myMaxTailWidth = theMaxTailWidth;
+}
+
+//=======================================================================
 //function : ClearModes
 //purpose  : 
 //=======================================================================
@@ -194,6 +215,7 @@ void ShapeFix_Wire::ClearModes()
   myFixSelfIntersectingEdgeMode = -1;
   myFixIntersectingEdgesMode = -1;
   myFixNonAdjacentIntersectingEdgesMode = -1;
+  myFixTailMode = 0;
 
   myFixReorderMode = -1;
   myFixSmallMode = -1;
@@ -227,6 +249,8 @@ void ShapeFix_Wire::ClearStatuses()
   myStatusGaps3d           = emptyStatus; //szv#9:S4244:19Aug99 new method introduced
   myStatusGaps2d           = emptyStatus; //szv#9:S4244:19Aug99 new method introduced
   myStatusClosed           = emptyStatus;
+  myStatusNotches = emptyStatus;
+  myStatusFixTails = emptyStatus;
 }
 
 //=======================================================================
@@ -361,11 +385,21 @@ Standard_Boolean ShapeFix_Wire::Perform()
   }
   
   //pdn - temporary to test
-  if ( NeedFix ( myFixNotchedEdgesMode, ReorderOK ) ) {
+  if (myFixTailMode <= 0 && NeedFix(myFixNotchedEdgesMode, ReorderOK))
+  {
     Fixed |= FixNotchedEdges();
     if(Fixed) FixShifted(); //skl 07.03.2002 for OCC180
   }
     
+  if (myFixTailMode != 0)
+  {
+    Fixed |= FixTails();
+    if (Fixed)
+    {
+      FixShifted();
+    }
+  }
+
   if ( NeedFix ( myFixSelfIntersectionMode, myClosedMode ) ) {
     Standard_Integer savFixIntersectingEdgesMode = myFixIntersectingEdgesMode;
     // switch off FixIntEdges if reorder not done
@@ -3322,3 +3356,171 @@ void ShapeFix_Wire::UpdateWire ()
     sbwd->Remove ( i-- );
   }
 }
+
+//=======================================================================
+//function : FixTails
+//purpose  :
+//=======================================================================
+Standard_Boolean ShapeFix_Wire::FixTails()
+{
+  if (myMaxTailWidth < 0 || !IsReady())
+  {
+    return Standard_False;
+  }
+
+  myLastFixStatus = ShapeExtend::EncodeStatus(ShapeExtend_OK);
+  if (!Context().IsNull())
+  {
+    UpdateWire();
+  }
+  Handle(ShapeExtend_WireData) aSEWD = WireData();
+  Standard_Integer aECount = NbEdges(), aENs[] = {aECount, 1};
+  Standard_Boolean aCheckAngle = Standard_True;
+  while (aECount >= 2 && aENs[1] <= aECount)
+  {
+    const TopoDS_Edge aEs[] = {aSEWD->Edge(aENs[0]), aSEWD->Edge(aENs[1])};
+    TopoDS_Edge aEParts[2][2];
+    if (!myAnalyzer->CheckTail(aEs[0], aEs[1],
+      aCheckAngle ? myMaxTailAngleSine : -1, myMaxTailWidth, MaxTolerance(),
+      aEParts[0][0], aEParts[0][1], aEParts[1][0], aEParts[1][1]))
+    {
+      aENs[0] = aENs[1]++;
+      aCheckAngle = Standard_True;
+      continue;
+    }
+
+    // Provide not less than 1 edge in the result wire.
+    Standard_Integer aSplitCounts[] =
+      {aEParts[0][1].IsNull() ? 0 : 1, aEParts[1][1].IsNull() ? 0 : 1};
+    const Standard_Integer aRemoveCount =
+      (aEParts[0][0].IsNull() ? 0 : 1) + (aEParts[1][0].IsNull() ? 0 : 1);
+    if (aECount + aSplitCounts[0] + aSplitCounts[1] < 1 + aRemoveCount)
+    {
+      aENs[0] = aENs[1]++;
+      aCheckAngle = Standard_True;
+      continue;
+    }
+
+    // Split the edges.
+    for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
+    {
+      if (aSplitCounts[aEI] == 0)
+      {
+        continue;
+      }
+
+      // Replace the edge by the wire of its parts in the shape.
+      const TopoDS_Edge aE = aEs[aEI];
+      if (!Context().IsNull())
+      {
+        TopoDS_Wire aEWire;
+        BRep_Builder().MakeWire(aEWire);
+        BRep_Builder().Add(aEWire, aEParts[aEI][0]);
+        BRep_Builder().Add(aEWire, aEParts[aEI][1]);
+        TopoDS_Edge aFE = TopoDS::Edge(aE.Oriented(TopAbs_FORWARD));
+        Context()->Replace(aFE, aEWire);
+      }
+
+      // Replace the edge by its parts in the edge wire.
+      const TopAbs_Orientation aOrient = aE.Orientation();
+      aEParts[aEI][0].Orientation(aOrient);
+      aEParts[aEI][1].Orientation(aOrient);
+      const Standard_Integer aFirstPI = (aOrient != TopAbs_REVERSED) ? 0 : 1;
+      const Standard_Integer aAdd =
+        (aEI == 0 || aENs[1] < aENs[0]) ? 0 : aSplitCounts[0];
+      aSEWD->Set(aEParts[aEI][aFirstPI], aENs[aEI] + aAdd);
+      aSEWD->Add(aEParts[aEI][1 - aFirstPI], aENs[aEI] + 1 + aAdd);
+    }
+
+    // Remove the tail.
+    if (aRemoveCount == 2)
+    {
+      aCheckAngle = Standard_True;
+      FixDummySeam(aENs[0] + aSplitCounts[0] +
+        ((aENs[0] < aENs[1]) ? 0 : aSplitCounts[1]));
+      if (!Context().IsNull())
+      {
+        UpdateWire();
+      }
+      myLastFixStatus |= ShapeExtend::EncodeStatus(ShapeExtend_DONE);
+
+      if (aSplitCounts[0] + aSplitCounts[1] == 2)
+      {
+        aENs[0] = aENs[1]++;
+        continue;
+      }
+
+      if (aSplitCounts[0] == aSplitCounts[1])
+      {
+        aECount -= 2;
+        if (aENs[1] >= 3)
+        {
+          --aENs[0];
+          --aENs[1];
+        }
+        else
+        {
+          aENs[0] = aECount;
+          aENs[1] = 1;
+        }
+        aCheckAngle = Standard_False;
+      }
+      else
+      {
+        --aECount;
+        if (aSplitCounts[0] != 0)
+        {
+          aENs[0] = (aENs[0] <= aECount) ? aENs[0] : aECount;
+        }
+        else
+        {
+          if (aENs[1] >= 3)
+          {
+            --aENs[0];
+            --aENs[1];
+          }
+          else
+          {
+            aENs[0] = aECount;
+            aENs[1] = 1;
+          }
+        }
+      }
+    }
+    else
+    {
+      aCheckAngle = Standard_False;
+      --aECount;
+      const Standard_Integer aRI = aEParts[0][0].IsNull() ? 1 : 0;
+      if (aSplitCounts[aRI] != 0)
+      {
+        if (aRI == 0)
+        {
+          if (aENs[1] >= 3)
+          {
+            --aENs[0];
+            --aENs[1];
+          }
+          else
+          {
+            aENs[0] = aECount;
+            aENs[1] = 1;
+          }
+        }
+        else
+        {
+          aENs[0] = (aENs[1] > 1) ? aENs[0] : aECount;
+        }
+      }
+      aSEWD->Remove(aENs[aRI] + ((aRI != 0 || aSplitCounts[0] == 0) ? 0 : 1));
+      if (!Context().IsNull())
+      {
+        Context()->Remove(aEs[aRI].Oriented(TopAbs_FORWARD));
+        UpdateWire();
+      }
+      myLastFixStatus |= ShapeExtend::EncodeStatus(ShapeExtend_DONE);
+    }
+  }
+  myStatusNotches = myLastFixStatus;
+  return ShapeExtend::DecodeStatus(myLastFixStatus, ShapeExtend_DONE);
+}
index 214a2cf..2ba6455 100644 (file)
@@ -406,6 +406,15 @@ inline  Standard_Integer& ShapeFix_Wire::FixNonAdjacentIntersectingEdgesMode()
 }
 
 //=======================================================================
+//function : FixTailMode
+//purpose  :
+//=======================================================================
+inline Standard_Integer& ShapeFix_Wire::FixTailMode()
+{
+  return myFixTailMode;
+}
+
+//=======================================================================
 //function : Status.. for high-level methods
 
 //=======================================================================
@@ -516,6 +525,16 @@ inline  Standard_Boolean ShapeFix_Wire::StatusNotches(const ShapeExtend_Status s
 {
   return ShapeExtend::DecodeStatus ( myStatusNotches, status ); 
 } 
+
+//=======================================================================
+//function : StatusFixTails
+//purpose  :
+//=======================================================================
+inline Standard_Boolean ShapeFix_Wire::StatusFixTails(const ShapeExtend_Status status) const
+{
+  return ShapeExtend::DecodeStatus(myStatusFixTails, status);
+}
+
 //=======================================================================
 //function : LastFixStatus - Status for low-level methods (common)
 //purpose  : 
index a1abd0d..bae3199 100644 (file)
@@ -752,15 +752,38 @@ static Standard_Boolean fixshape (const Handle(ShapeProcess_Context)& context)
   sfw->FixSeamMode()                = ctx->IntegerVal ( "FixSeamMode", -1 );
   sfw->FixSameParameterMode()        = ctx->IntegerVal ( "FixEdgeSameParameterMode", -1 );
   sfw->FixNotchedEdgesMode()         = ctx->IntegerVal ( "FixNotchedEdgesMode", -1 );
+  sfw->FixTailMode() = ctx->IntegerVal("FixTailMode", 0);
+  sfw->SetMaxTailAngle(ctx->RealVal("MaxTailAngle", 0) * (M_PI / 180));
+  sfw->SetMaxTailWidth(ctx->RealVal("MaxTailWidth", -1));
   sfw->FixSelfIntersectingEdgeMode() = ctx->IntegerVal ( "FixSelfIntersectingEdgeMode", -1 );
   sfw->FixIntersectingEdgesMode()    = ctx->IntegerVal ( "FixIntersectingEdgesMode", -1 );
   sfw->FixNonAdjacentIntersectingEdgesMode() = ctx->IntegerVal ( "FixNonAdjacentIntersectingEdgesMode", -1 );
-  
+  if (sfw->FixTailMode() == 1)
+  {
+    sfw->FixTailMode() = 0;
+    sfs->Init(ctx->Result());
+    sfs->Perform(ctx->Progress());
+    sfw->FixTailMode() = 1;
+    if (!ctx->Progress().IsNull() && ctx->Progress()->UserBreak())
+    {
+      return Standard_False;
+    }
+
+    TopoDS_Shape result = sfs->Shape();
+    if (result != ctx->Result() ||
+      (!msg.IsNull() && !msg->MapShape().IsEmpty()))
+    {
+      ctx->RecordModification(sfs->Context(), msg);
+      ctx->SetResult(result);
+    }
+  }
+
   sfs->Init(ctx->Result());
   sfs->Perform(ctx->Progress());
-
-  if ( !ctx->Progress().IsNull() && ctx->Progress()->UserBreak() )
+  if (!ctx->Progress().IsNull() && ctx->Progress()->UserBreak())
+  {
     return Standard_False;
+  }
 
   TopoDS_Shape result = sfs->Shape();
   if (( result != ctx->Result() ) ||
index 9a02245..6f04a84 100755 (executable)
@@ -51,6 +51,9 @@ FromSTEP.FixShape.FixSeamMode                 : -1
 FromSTEP.FixShape.FixShiftedMode               : -1
 FromSTEP.FixShape.FixEdgeSameParameterMode     :  0
 FromSTEP.FixShape.FixNotchedEdgesMode          : -1
+FromSTEP.FixShape.FixTailMode : 0
+FromSTEP.FixShape.MaxTailAngle : 0
+FromSTEP.FixShape.MaxTailWidth : -1
 FromSTEP.FixShape.FixSelfIntersectingEdgeMode  : -1
 FromSTEP.FixShape.FixIntersectingEdgesMode     : -1
 FromSTEP.FixShape.FixNonAdjacentIntersectingEdgesMode : -1
index 41d89bd..8139979 100755 (executable)
@@ -11,3 +11,10 @@ if { [info exists test_image ] == 0 } {
    set test_image photo
 }
 
+proc checklength {theShape theLength} {
+  set aLengthDump [uplevel lprops $theShape -full]
+  regexp {Mass\s*:\s*([-0-9.+eE]+)} $aLengthDump dummy aLength
+  if {abs($aLength - $theLength) > $theLength * 1e-14} {
+    puts "Error: result length is too different."
+  }
+}
index 35f01fb..e899bce 100755 (executable)
@@ -1,10 +1,16 @@
-clear
-smallview
-if { [isdraw result] } {
+ if { [isdraw result] } {
+   clear
+   smallview
    donly result
+   fit
+   xwd $imagedir/${test_image}.png
+} elseif { [isdraw r] } {
+   pload VISUALIZATION
+   vinit
+   vdisplay r
+   vfit
+   vdump $imagedir/${test_image}.png
 } else {
    puts "Error : the resulting shape is not done."
 }
-fit
-xwd $imagedir/${test_image}.png
 puts "TEST COMPLETED"
index 280a03f..574cf5e 100644 (file)
@@ -17,3 +17,5 @@
 017 surface_to_revolution_advanced
 018 surface_to_revolution_standard
 019 drop_small_solids
+020 wire_tails_composed
+021 wire_tails_real
diff --git a/tests/heal/wire_tails_composed/A1 b/tests/heal/wire_tails_composed/A1
new file mode 100644 (file)
index 0000000..2fc3366
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 -1 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v1 v2 v3 v1
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 0.7
+
+checknbshapes  r  -vertex 3  -edge 3  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 9.054743851305652
diff --git a/tests/heal/wire_tails_composed/A10 b/tests/heal/wire_tails_composed/A10
new file mode 100644 (file)
index 0000000..c21ff32
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 -2 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v3 v2 v1 v3
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 1
+
+checknbshapes  r  -vertex 2  -edge 2  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 6.1622776601683791
diff --git a/tests/heal/wire_tails_composed/A11 b/tests/heal/wire_tails_composed/A11
new file mode 100644 (file)
index 0000000..fd786b4
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 -2 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v2 v1 v3 v2
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 1
+
+checknbshapes  r  -vertex 2  -edge 2  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 6.1622776601683791
diff --git a/tests/heal/wire_tails_composed/A12 b/tests/heal/wire_tails_composed/A12
new file mode 100644 (file)
index 0000000..1de5f15
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 -2 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v1 v3 v2 v1
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 1
+
+checknbshapes  r  -vertex 2  -edge 2  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 6.1622776601683791
diff --git a/tests/heal/wire_tails_composed/A13 b/tests/heal/wire_tails_composed/A13
new file mode 100644 (file)
index 0000000..88ac075
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 0 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v1 v2 v3 v1
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 1.5
+
+checknbshapes  r  -vertex 1  -edge 1  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 1.4142135623730949
diff --git a/tests/heal/wire_tails_composed/A14 b/tests/heal/wire_tails_composed/A14
new file mode 100644 (file)
index 0000000..99953db
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 0 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v2 v3 v1 v2
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 1.5
+
+checknbshapes  r  -vertex 1  -edge 1  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 1.4142135623730949
diff --git a/tests/heal/wire_tails_composed/A15 b/tests/heal/wire_tails_composed/A15
new file mode 100644 (file)
index 0000000..8db6140
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 0 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v3 v1 v2 v3
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 1.5
+
+checknbshapes  r  -vertex 1  -edge 1  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 1.4142135623730949
diff --git a/tests/heal/wire_tails_composed/A16 b/tests/heal/wire_tails_composed/A16
new file mode 100644 (file)
index 0000000..6204ccb
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 0 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v3 v2 v1 v3
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 1.5
+
+checknbshapes  r  -vertex 1  -edge 1  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 1.4142135623730949
diff --git a/tests/heal/wire_tails_composed/A17 b/tests/heal/wire_tails_composed/A17
new file mode 100644 (file)
index 0000000..32fd6b4
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 0 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v2 v1 v3 v2
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 1.5
+
+checknbshapes  r  -vertex 1  -edge 1  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 1.4142135623730949
diff --git a/tests/heal/wire_tails_composed/A18 b/tests/heal/wire_tails_composed/A18
new file mode 100644 (file)
index 0000000..43704a8
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 0 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v1 v3 v2 v1
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 1.5
+
+checknbshapes  r  -vertex 1  -edge 1  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 1.4142135623730949
diff --git a/tests/heal/wire_tails_composed/A19 b/tests/heal/wire_tails_composed/A19
new file mode 100644 (file)
index 0000000..0c45b11
--- /dev/null
@@ -0,0 +1,17 @@
+vertex v1 -1 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+vertex v4 1 1 5
+polyvertex w1 v1 v3 v2 v1
+mkplane s1 w1
+polyvertex w2 v1 v2 v4 v1
+mkplane s2 w2
+polyvertex w3 v2 v3 v4 v2
+mkplane s3 w3
+polyvertex w4 v1 v4 v3 v1
+mkplane s4 w4
+sewing s s1 s2 s3 s4
+fixshape  r  s  -maxtaila 10  -maxtailw 0.7
+
+checknbshapes  r  -vertex 5  -edge 7  -wire 4  -face 4  -shell 1  -solid 0  -compsolid 0  -compound 0
+checklength r 69.237606465667483
diff --git a/tests/heal/wire_tails_composed/A2 b/tests/heal/wire_tails_composed/A2
new file mode 100644 (file)
index 0000000..c5f0797
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 -1 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v2 v3 v1 v2
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 0.7
+
+checknbshapes  r  -vertex 3  -edge 3  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 9.054743851305652
diff --git a/tests/heal/wire_tails_composed/A3 b/tests/heal/wire_tails_composed/A3
new file mode 100644 (file)
index 0000000..b2e4b0b
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 -1 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v3 v1 v2 v3
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 0.7
+
+checknbshapes  r  -vertex 3  -edge 3  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 9.054743851305652
diff --git a/tests/heal/wire_tails_composed/A4 b/tests/heal/wire_tails_composed/A4
new file mode 100644 (file)
index 0000000..ad3c08c
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 -1 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v3 v2 v1 v3
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 0.7
+
+checknbshapes  r  -vertex 3  -edge 3  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 9.0547440573886373
diff --git a/tests/heal/wire_tails_composed/A5 b/tests/heal/wire_tails_composed/A5
new file mode 100644 (file)
index 0000000..2447239
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 -1 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v2 v1 v3 v2
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 0.7
+
+checknbshapes  r  -vertex 3  -edge 3  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 9.0547440573886373
diff --git a/tests/heal/wire_tails_composed/A6 b/tests/heal/wire_tails_composed/A6
new file mode 100644 (file)
index 0000000..17ea7c9
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 -1 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v1 v3 v2 v1
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 0.7
+
+checknbshapes  r  -vertex 3  -edge 3  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 9.0547440573886373
diff --git a/tests/heal/wire_tails_composed/A7 b/tests/heal/wire_tails_composed/A7
new file mode 100644 (file)
index 0000000..d8eb4d2
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 -2 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v1 v2 v3 v1
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 1
+
+checknbshapes  r  -vertex 2  -edge 2  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 6.1622776601683791
diff --git a/tests/heal/wire_tails_composed/A8 b/tests/heal/wire_tails_composed/A8
new file mode 100644 (file)
index 0000000..7e8ae51
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 -2 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v2 v3 v1 v2
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 1
+
+checknbshapes  r  -vertex 2  -edge 2  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 6.1622776601683791
diff --git a/tests/heal/wire_tails_composed/A9 b/tests/heal/wire_tails_composed/A9
new file mode 100644 (file)
index 0000000..11e5a58
--- /dev/null
@@ -0,0 +1,9 @@
+vertex v1 -2 0 0
+vertex v2 9 0 0
+vertex v3 1 1 0
+polyvertex w v3 v1 v2 v3
+mkplane s w
+fixshape  r  s  -maxtaila 10  -maxtailw 1
+
+checknbshapes  r  -vertex 2  -edge 2  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 6.1622776601683791
diff --git a/tests/heal/wire_tails_real/A1 b/tests/heal/wire_tails_real/A1
new file mode 100644 (file)
index 0000000..ea3f42f
--- /dev/null
@@ -0,0 +1,5 @@
+restore [locate_data_file  bug26261_a_2574.brep] s
+fixshape  r  s  -maxtaila 1  -maxtailw 6e-3
+
+checknbshapes  r  -vertex 16  -edge 16  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 17.514170299083325
diff --git a/tests/heal/wire_tails_real/A2 b/tests/heal/wire_tails_real/A2
new file mode 100644 (file)
index 0000000..74c0bb9
--- /dev/null
@@ -0,0 +1,5 @@
+restore [locate_data_file  bug26261_a_3380.brep] s
+fixshape  r  s  -maxtaila 1  -maxtailw 3e-3
+
+checknbshapes  r  -vertex 5  -edge 5  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 1.9646975436380054
diff --git a/tests/heal/wire_tails_real/A3 b/tests/heal/wire_tails_real/A3
new file mode 100644 (file)
index 0000000..7e25f52
--- /dev/null
@@ -0,0 +1,5 @@
+restore [locate_data_file  bug26261_notched_1.brep] s
+fixshape  r  s  -maxtaila 1  -maxtailw 1e-4
+
+checknbshapes  r  -vertex 7  -edge 7  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 5.4302952062350922
diff --git a/tests/heal/wire_tails_real/A4 b/tests/heal/wire_tails_real/A4
new file mode 100644 (file)
index 0000000..b69fba5
--- /dev/null
@@ -0,0 +1,5 @@
+restore [locate_data_file  bug26261_notched_2.brep] s
+fixshape  r  s  -maxtaila 1  -maxtailw 1e-2
+
+checknbshapes  r  -vertex 3  -edge 3  -wire 1  -face 1  -shell 0  -solid 0  -compsolid 0  -compound 0
+checklength r 21.767418596938622
diff --git a/tests/heal/wire_tails_real/A5 b/tests/heal/wire_tails_real/A5
new file mode 100644 (file)
index 0000000..065566a
--- /dev/null
@@ -0,0 +1,8 @@
+pload XDE
+
+stepread [locate_data_file bug26261_ca07771-040x.stp] s *
+renamevar s_1 s
+fixshape  r  s  -maxtaila 1  -maxtailw 1e-3
+
+checknbshapes  r  -vertex 25950  -edge 41999  -wire 16519  -face 16205  -shell 51  -solid 1  -compsolid 0  -compound 2
+checklength r 127197.57657573155
diff --git a/tests/heal/wire_tails_real/A6 b/tests/heal/wire_tails_real/A6
new file mode 100644 (file)
index 0000000..b19706c
--- /dev/null
@@ -0,0 +1,8 @@
+pload XDE
+
+stepread [locate_data_file bug26261_lower_2.stp] s *
+renamevar s_1 s
+fixshape  r  s  1e-3  1  -maxtaila 6  -maxtailw 1e-3
+
+checknbshapes  r  -vertex 257  -edge 395  -wire 146  -face 137  -shell 1  -solid 1  -compsolid 0  -compound 0
+checklength r 4611.0742231217555
diff --git a/tests/heal/wire_tails_real/A7 b/tests/heal/wire_tails_real/A7
new file mode 100644 (file)
index 0000000..9d596c2
--- /dev/null
@@ -0,0 +1,8 @@
+pload XDE
+
+stepread [locate_data_file bug26261_mmg-m-cv-qubit.stp] s *
+renamevar s_1 s
+fixshape  r  s  1e-3  1  -maxtaila 6  -maxtailw 1e-3
+
+checknbshapes  r  -vertex 8494  -edge 13832  -wire 5955  -face 5466  -shell 1  -solid 1  -compsolid 0  -compound 0
+checklength r 69141.057126027736