0028968: Incorrect offset for the faces with singularities
authorabv <abv@opencascade.com>
Fri, 25 Aug 2017 11:10:02 +0000 (14:10 +0300)
committerbugmaster <bugmaster@opencascade.com>
Wed, 30 Aug 2017 10:52:56 +0000 (13:52 +0300)
Simple offset algorithm (BRepOffset_MakeSimpleOffset) is improved to handle the case when bspline surface has imprecise singularity at one of sides (when side is degenerated but not exactly to one point).
In such case, the algorithm tries to collapse all poles of singular side of the surface to the same point; this allows avoiding flapping of normal due to small fluctuations of surface.

If face being offset contains degenerated edges, then check for singularity is done using position and tolerance of corresponding vertices.
In addition, each side is checked with some user-defined tolerance (by default Precision::Confusion()); this helps to process cases when no edge is located at that side or if such edge is not encoded as degenerated.
New parameter Tolerance is introduced for that in BRepOffset_MakeSimpleOffset class.

Tests added:
bugs modelg_7 bug28968 - on isolated faces as reported in the issue, mostly for visual check (absence of loops)
offset simple F01-05 - on original shells, checking tolerances of resulting shell

20 files changed:
src/BRepOffset/BRepOffset.cxx
src/BRepOffset/BRepOffset.hxx
src/BRepOffset/BRepOffset_MakeSimpleOffset.cxx
src/BRepOffset/BRepOffset_MakeSimpleOffset.hxx
src/BRepOffset/BRepOffset_SimpleOffset.cxx
src/BRepOffset/BRepOffset_SimpleOffset.hxx
src/BRepTest/BRepTest_FeatureCommands.cxx
src/BRepTest/BRepTest_OtherCommands.cxx
src/DrawResources/CheckCommands.tcl
src/ViewerTest/ViewerTest.cxx
tests/bugs/modalg_7/bug28968 [new file with mode: 0644]
tests/offset/simple/A04
tests/offset/simple/A11
tests/offset/simple/F01 [new file with mode: 0644]
tests/offset/simple/F02 [new file with mode: 0644]
tests/offset/simple/F03 [new file with mode: 0644]
tests/offset/simple/F04 [new file with mode: 0644]
tests/offset/simple/F05 [new file with mode: 0644]
tests/offset/simple/begin
tests/offset/simple/end

index 6270a8b..7fac35f 100644 (file)
@@ -16,6 +16,7 @@
 
 
 #include <BRepOffset.hxx>
+#include <BRep_Tool.hxx>
 #include <Geom_BSplineSurface.hxx>
 #include <Geom_ConicalSurface.hxx>
 #include <Geom_CylindricalSurface.hxx>
 #include <gp_Ax3.hxx>
 #include <gp_Dir.hxx>
 #include <gp_Vec.hxx>
+#include <NCollection_LocalArray.hxx>
 #include <Precision.hxx>
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_ListOfShape.hxx>
+#include <TopoDS_Vertex.hxx>
 
 //=======================================================================
 //function : Surface
 //purpose  : 
 //=======================================================================
 Handle(Geom_Surface) BRepOffset::Surface(const Handle(Geom_Surface)& Surface,
-                                        const Standard_Real Offset,
-                                              BRepOffset_Status& theStatus)
+                                                            const Standard_Real Offset,
+                                         BRepOffset_Status& theStatus,
+                                         Standard_Boolean allowC0)
 {
   Standard_Real Tol = Precision::Confusion();
 
@@ -152,17 +162,158 @@ Handle(Geom_Surface) BRepOffset::Surface(const Handle(Geom_Surface)& Surface,
       Handle(Geom_RectangularTrimmedSurface)::DownCast(Surface);
     Standard_Real U1,U2,V1,V2;
     S->Bounds(U1,U2,V1,V2);
-    Handle(Geom_Surface) Off = BRepOffset::Surface (S->BasisSurface(), Offset, theStatus);
+    Handle(Geom_Surface) Off = BRepOffset::Surface (S->BasisSurface(), Offset, theStatus, allowC0);
     Result = new Geom_RectangularTrimmedSurface (Off,U1,U2,V1,V2);
   }
   else if (TheType == STANDARD_TYPE(Geom_OffsetSurface)) {
   }
 
   if ( Result.IsNull()) {
-    Result = new Geom_OffsetSurface( Surface, Offset);
+    Result = new Geom_OffsetSurface( Surface, Offset, allowC0);
   }
   
   return Result;
 }
 
+//=======================================================================
+//function : CollapseSingularities
+//purpose  : 
+//=======================================================================
+Handle(Geom_Surface) BRepOffset::CollapseSingularities (const Handle(Geom_Surface)& theSurface,
+                                                        const TopoDS_Face& theFace,
+                                                        Standard_Real thePrecision)
+{
+  // check surface type to see if it can be processed
+  Handle(Standard_Type) aType = theSurface->DynamicType();
+  if (aType != STANDARD_TYPE(Geom_BSplineSurface))
+  {
+    // for the moment, only bspline surfaces are treated;
+    // in the future, bezier surfaces and surfaces of revolution can be also handled
+    return theSurface;
+  }
+
+  // find singularities (vertices of degenerated edges)
+  NCollection_List<gp_Pnt> aDegenPnt;
+  NCollection_List<Standard_Real> aDegenTol;
+  for (TopExp_Explorer anExp (theFace, TopAbs_EDGE); anExp.More(); anExp.Next())
+  {
+    TopoDS_Edge anEdge = TopoDS::Edge (anExp.Current());
+    if (! BRep_Tool::Degenerated (anEdge))
+    {
+      continue;
+    }
+    TopoDS_Vertex aV1, aV2;
+    TopExp::Vertices (anEdge, aV1, aV2);
+    if (! aV1.IsSame (aV2))
+    {
+      continue;
+    }
+
+    aDegenPnt.Append (BRep_Tool::Pnt (aV1));
+    aDegenTol.Append (BRep_Tool::Tolerance (aV1));
+  }
+
+  // iterate by sides of the surface
+  if (aType == STANDARD_TYPE(Geom_BSplineSurface))
+  {
+    Handle(Geom_BSplineSurface) aBSpline = Handle(Geom_BSplineSurface)::DownCast (theSurface);
+    const TColgp_Array2OfPnt& aPoles = aBSpline->Poles();
+    
+    Handle(Geom_BSplineSurface) aCopy;
+
+    // iterate by sides: {U=0; V=0; U=1; V=1}
+    Standard_Integer RowStart[4] = {aPoles.LowerRow(), aPoles.LowerRow(), aPoles.UpperRow(), aPoles.LowerRow()};
+    Standard_Integer ColStart[4] = {aPoles.LowerCol(), aPoles.LowerCol(), aPoles.LowerCol(), aPoles.UpperCol()};
+    Standard_Integer RowStep[4]  = {0, 1, 0, 1};
+    Standard_Integer ColStep[4]  = {1, 0, 1, 0};
+    Standard_Integer NbSteps[4]  = {aPoles.RowLength(), aPoles.ColLength(), aPoles.RowLength(), aPoles.ColLength()};
+    for (Standard_Integer iSide = 0; iSide < 4; iSide++)
+    {
+      // compute center of gravity of side poles
+      gp_XYZ aSum;
+      for (int iPole = 0; iPole < NbSteps[iSide]; iPole++)
+      {
+        aSum += aPoles (RowStart[iSide] + iPole * RowStep[iSide], ColStart[iSide] + iPole * ColStep[iSide]).XYZ();
+      }
+      gp_Pnt aCenter (aSum / NbSteps[iSide]);
 
+      // determine if all poles of the side fit into:
+      Standard_Boolean isCollapsed = Standard_True; // aCenter precisely (with gp::Resolution())
+      Standard_Boolean isSingular = Standard_True;  // aCenter with thePrecision
+      NCollection_LocalArray<Standard_Boolean,4> isDegenerated (aDegenPnt.Extent()); // degenerated vertex
+      for (size_t iDegen = 0; iDegen < isDegenerated.Size(); ++iDegen) isDegenerated[iDegen] = Standard_True;
+      for (int iPole = 0; iPole < NbSteps[iSide]; iPole++)
+      {
+        const gp_Pnt& aPole = aPoles (RowStart[iSide] + iPole * RowStep[iSide], ColStart[iSide] + iPole * ColStep[iSide]);
+
+        // distance from CG
+        Standard_Real aDistCG = aCenter.Distance (aPole);
+        if (aDistCG > gp::Resolution())
+          isCollapsed = Standard_False;
+        if (aDistCG > thePrecision)
+          isSingular = Standard_False;
+
+        // distances from degenerated points
+        NCollection_List<gp_Pnt>::Iterator aDegPntIt (aDegenPnt);
+        NCollection_List<Standard_Real>::Iterator aDegTolIt(aDegenTol);
+        for (size_t iDegen = 0; iDegen < isDegenerated.Size(); aDegPntIt.Next(), aDegTolIt.Next(), ++iDegen)
+        {
+          if (isDegenerated[iDegen] && aDegPntIt.Value().Distance (aPole) >= aDegTolIt.Value())
+          {
+            isDegenerated[iDegen] = Standard_False;
+          }
+        }
+      }
+      if (isCollapsed)
+      {
+        continue; // already Ok, nothing to be done
+      }
+
+      // decide to collapse the side: either if it is singular with thePrecision,
+      // or if it fits into one (and only one) degenerated point
+      if (! isSingular)
+      {
+        Standard_Integer aNbFit = 0;
+        NCollection_List<gp_Pnt>::Iterator aDegPntIt (aDegenPnt);
+        NCollection_List<Standard_Real>::Iterator aDegTolIt(aDegenTol);
+        for (size_t iDegen = 0; iDegen < isDegenerated.Size(); ++iDegen)
+        {
+          if (isDegenerated[iDegen])
+          {
+            // remove degenerated point as soon as it fits at least one side, to prevent total collapse
+            aDegenPnt.Remove (aDegPntIt);
+            aDegenTol.Remove (aDegTolIt);
+            aNbFit++;
+          }
+          else
+          {
+            aDegPntIt.Next();
+            aDegTolIt.Next();
+          }
+        }
+
+        // if side fits more than one degenerated vertex, do not collapse it
+        // to be on the safe side
+        isSingular = (aNbFit == 1);
+      }
+      
+      // do collapse
+      if (isSingular)
+      {
+        if (aCopy.IsNull())
+        {
+          aCopy = Handle(Geom_BSplineSurface)::DownCast (theSurface->Copy());
+        }
+        for (int iPole = 0; iPole < NbSteps[iSide]; iPole++)
+        {
+          aCopy->SetPole (RowStart[iSide] + iPole * RowStep[iSide], ColStart[iSide] + iPole * ColStep[iSide], aCenter);
+        }
+      }
+    }
+
+    if (! aCopy.IsNull())
+      return aCopy;
+  }
+
+  return theSurface;
+}
index e037d03..09fde55 100644 (file)
 #include <Standard_DefineAlloc.hxx>
 #include <Standard_Handle.hxx>
 
-#include <Standard_Real.hxx>
 #include <BRepOffset_Status.hxx>
-class Geom_Surface;
-class BRepOffset_MakeOffset;
-class BRepOffset_Inter3d;
-class BRepOffset_Inter2d;
-class BRepOffset_Offset;
-class BRepOffset_Analyse;
-class BRepOffset_MakeLoops;
-class BRepOffset_Tool;
-class BRepOffset_Interval;
 
+class Geom_Surface;
+class TopoDS_Face;
 
+//! Auxiliary tools for offset algorithms
 
 class BRepOffset 
 {
 public:
 
-  DEFINE_STANDARD_ALLOC
-
-  
   //! returns   the  Offset  surface  computed from  the
   //! surface <Surface> at an OffsetDistance <Offset>.
   //!
@@ -50,37 +40,29 @@ public:
   //!
   //! If  no particular  case  is detected, the returned
   //! surface will have the Type Geom_OffsetSurface.
-  Standard_EXPORT static Handle(Geom_Surface) Surface (const Handle(Geom_Surface)& Surface, const Standard_Real Offset, BRepOffset_Status& theStatus);
-
-
-
-
-protected:
-
-
-
-
-
-private:
-
-
-
-
-friend class BRepOffset_MakeOffset;
-friend class BRepOffset_Inter3d;
-friend class BRepOffset_Inter2d;
-friend class BRepOffset_Offset;
-friend class BRepOffset_Analyse;
-friend class BRepOffset_MakeLoops;
-friend class BRepOffset_Tool;
-friend class BRepOffset_Interval;
+  //! Parameter allowC0 is then passed as last argument to 
+  //! constructor of Geom_OffsetSurface.
+  Standard_EXPORT static Handle(Geom_Surface) Surface (const Handle(Geom_Surface)& Surface, 
+                                                       const Standard_Real Offset, 
+                                                       BRepOffset_Status& theStatus,
+                                                       Standard_Boolean allowC0 = Standard_False);
+
+  //! Preprocess surface to be offset (bspline, bezier, or revolution based on
+  //! bspline or bezier curve), by collapsing each singular side to single point.
+  //!
+  //! This is to avoid possible flipping of normal at the singularity 
+  //! of the surface due to non-zero distance between the poles that
+  //! logically should be in one point (singularity).
+  //! 
+  //! The (parametric) side of the surface is considered to be singularity if face 
+  //! has degenerated edge whose vertex encompasses (by its tolerance) all points on that side,
+  //! or if all poles defining that side fit into sphere with radius thePrecision.
+  //!
+  //! Returns either original surface or its modified copy (if some poles have been moved).
+  Standard_EXPORT static Handle(Geom_Surface) CollapseSingularities (const Handle(Geom_Surface)& theSurface, 
+                                                                     const TopoDS_Face& theFace,
+                                                                     Standard_Real thePrecision);
 
 };
 
-
-
-
-
-
-
 #endif // _BRepOffset_HeaderFile
index 3b89a5a..e48a05c 100644 (file)
@@ -50,7 +50,9 @@
 //purpose  : Constructor
 //=============================================================================
 BRepOffset_MakeSimpleOffset::BRepOffset_MakeSimpleOffset()
-: myIsBuildSolid(Standard_False),
+: myOffsetValue(0.),
+  myTolerance(Precision::Confusion()),
+  myIsBuildSolid(Standard_False),
   myMaxAngle(0.0),
   myError(BRepOffsetSimple_OK),
   myIsDone(Standard_False)
@@ -66,6 +68,7 @@ BRepOffset_MakeSimpleOffset::BRepOffset_MakeSimpleOffset(const TopoDS_Shape& the
                                                          const Standard_Real theOffsetValue)
 : myInputShape(theInputShape),
   myOffsetValue(theOffsetValue),
+  myTolerance(Precision::Confusion()),
   myIsBuildSolid(Standard_False),
   myMaxAngle(0.0),
   myError(BRepOffsetSimple_OK),
@@ -177,7 +180,7 @@ void BRepOffset_MakeSimpleOffset::Perform()
     ComputeMaxAngle();
 
   myBuilder.Init(myInputShape);
-  Handle(BRepOffset_SimpleOffset) aMapper = new BRepOffset_SimpleOffset(myInputShape, myOffsetValue);
+  Handle(BRepOffset_SimpleOffset) aMapper = new BRepOffset_SimpleOffset(myInputShape, myOffsetValue, myTolerance);
   myBuilder.Perform(aMapper);
 
   if (!myBuilder.IsDone())
index 83d3fc2..ab89b7e 100644 (file)
@@ -95,6 +95,12 @@ public:
   //! Sets offset value.
   void SetOffsetValue(const Standard_Real theOffsetValue) { myOffsetValue = theOffsetValue; }
 
+  //! Gets tolerance (used for handling singularities).
+  Standard_Real GetTolerance() const { return myTolerance; }
+
+  //! Sets tolerance (used for handling singularities).
+  void SetTolerance (const Standard_Real theValue) { myTolerance = theValue; }
+
   //! Gets done state.
   Standard_Boolean IsDone() const { return myIsDone; } 
 
@@ -134,6 +140,9 @@ private:
   //! Offset value.
   Standard_Real myOffsetValue;
 
+  //! Tolerance (for singularities)
+  Standard_Real myTolerance;
+
   //! Solid building flag. True means solid construction.
   Standard_Boolean myIsBuildSolid;
 
index 6b63c84..ff585e5 100644 (file)
@@ -21,6 +21,7 @@
 #include <BRepBuilderAPI_MakeEdge.hxx>
 #include <BRepLib.hxx>
 #include <BRep_Tool.hxx>
+#include <BRepOffset.hxx>
 #include <Geom_OffsetSurface.hxx>
 #include <GeomAdaptor_Curve.hxx>
 #include <Geom2dAdaptor_HCurve.hxx>
@@ -42,8 +43,10 @@ static const Standard_Integer NCONTROL=22;
 //purpose  : Constructor
 //=============================================================================
 BRepOffset_SimpleOffset::BRepOffset_SimpleOffset(const TopoDS_Shape& theInputShape,
-                                                 const Standard_Real theOffsetValue)
-: myOffsetValue(theOffsetValue)
+                                                 const Standard_Real theOffsetValue,
+                                                 const Standard_Real theTolerance)
+: myOffsetValue(theOffsetValue),
+  myTolerance(theTolerance)
 {
   FillOffsetData(theInputShape);
 }
@@ -223,6 +226,7 @@ void BRepOffset_SimpleOffset::FillFaceData(const TopoDS_Face& theFace)
   // Any existing transformation is applied to the surface.
   // New face will have null transformation.
   Handle(Geom_Surface) aS = BRep_Tool::Surface(theFace);
+  aS = BRepOffset::CollapseSingularities (aS, theFace, myTolerance);
 
   // Take into account face orientation.
   Standard_Real aMult = 1.0;
index 423f1fd..ea45b2a 100644 (file)
@@ -46,8 +46,12 @@ public:
   DEFINE_STANDARD_RTTI_INLINE(BRepOffset_SimpleOffset, BRepTools_Modification)
 
   //! Constructor.
+  //! @param theInputShape shape to be offset
+  //! @param theOffsetValue offset distance (signed)
+  //! @param theTolerance tolerance for handling singular points
   Standard_EXPORT BRepOffset_SimpleOffset(const TopoDS_Shape& theInputShape,
-                                          const Standard_Real theOffsetValue);
+                                          const Standard_Real theOffsetValue,
+                                          const Standard_Real theTolerance);
 
   //! Returns Standard_True  if  the face  <F> has  been
   //! modified.  In this  case, <S> is the new geometric
@@ -178,6 +182,9 @@ private:
 
   //! Offset value.
   Standard_Real myOffsetValue;
+
+  //! Tolerance.
+  Standard_Real myTolerance;
 };
 
 #endif // _BRepOffset_SimpleOffset_HeaderFile
index 7f5f4d1..4dfa14a 100644 (file)
@@ -2247,9 +2247,9 @@ static Standard_Integer ComputeSimpleOffset(Draw_Interpretor& theCommands,
                                             Standard_Integer narg, 
                                             const char** a)
 {
-  if (narg != 4 && narg != 5)
+  if (narg < 4)
   {
-    theCommands << "offsetshapesimple result shape offsetvalue [solid]\n";
+    theCommands << "offsetshapesimple result shape offsetvalue [solid] [tolerance=1e-7]\n";
     return 1;
   }
 
@@ -2267,12 +2267,13 @@ static Standard_Integer ComputeSimpleOffset(Draw_Interpretor& theCommands,
     return 0;
   }
 
-  BRepOffset_MakeSimpleOffset aMaker(aShape, anOffsetValue);
-  if (narg == 5 && !strcasecmp(a[4],"solid") )
-  {
-    aMaker.SetBuildSolidFlag(Standard_True);
-  }
+  Standard_Boolean makeSolid = (narg > 4 && !strcasecmp(a[4],"solid"));
+  int iTolArg = (makeSolid ? 5 : 4);
+  Standard_Real aTol = (narg > iTolArg ? Draw::Atof(a[iTolArg]) : Precision::Confusion());
 
+  BRepOffset_MakeSimpleOffset aMaker(aShape, anOffsetValue);
+  aMaker.SetTolerance (aTol);
+  aMaker.SetBuildSolidFlag(makeSolid);
   aMaker.Perform();
 
   if (!aMaker.IsDone())
@@ -2432,6 +2433,6 @@ void BRepTest::FeatureCommands (Draw_Interpretor& theCommands)
                  __FILE__,BOSS);
 
   theCommands.Add("offsetshapesimple", 
-                  "offsetshapesimple result shape offsetvalue [solid]",
+                  "offsetshapesimple result shape offsetvalue [solid] [tolerance=1e-7]",
                   __FILE__, ComputeSimpleOffset);
 }
index 8ba26a7..eccd3eb 100644 (file)
@@ -72,7 +72,6 @@
 
 #include <BRepTools.hxx>
 #include <BRepIntCurveSurface_Inter.hxx>
-#include <BRepOffset.hxx>
 #include <BRepOffset_MakeOffset.hxx>
 #include <BRepClass3d_SolidClassifier.hxx>
 #include <GeomAdaptor_Curve.hxx>
index c6a06c8..b9acbb1 100644 (file)
@@ -359,15 +359,18 @@ proc checkfreebounds {shape ref_value args} {
 }
 
 help checkmaxtol {
-  Compare max tolerance of shape with reference value.
-  Command returns max tolerance of the shape.
+  Returns max tolerance of the shape and prints error message if specified
+  criteria are not satisfied.
 
   Use: checkmaxtol shape [options...]
-  Allowed options are:
-    -ref: reference value of maximum tolerance.
-    -source: list of shapes to compare with, e.g.: -source {shape1 shape2 shape3}
-    -min_tol: minimum tolerance for comparison.
-    -multi_tol: tolerance multiplier.
+
+  Options specify criteria for checking the maximal tolerance value:
+    -ref <value>: check it to be equal to reference value.
+    -min_tol <value>: check it to be not greater than specified value.
+    -source <list of shapes>: check it to be not greater than 
+            maximal tolerance of specified shape(s)
+    -multi_tol <value>: additional multiplier for value specified by -min_tol 
+               or -shapes options.
 }
 
 proc checkmaxtol {shape args} {
@@ -764,9 +767,10 @@ help checkview {
     -display shapename: display shape with name 'shapename'
     -3d: display shape in 3d viewer
     -2d [ v2d / smallview ]: display shape in 2d viewer (default viewer is a 'smallview')
-    -path PATH: location of saved screenshot of viewer
     -vdispmode N: it is possible to set vdispmode for 3d viewer (default value is 1)
     -screenshot: procedure will try to make screenshot of already created viewer
+    -path <path>: location of saved screenshot of viewer
+
     Procedure can check some property of shape (length, area or volume) and compare it with some value N:
       -l [N]
       -s [N]
index c290f62..b61329a 100644 (file)
@@ -420,7 +420,6 @@ void GetTypeAndSignfromString (const char* name,AIS_KindOfInteractive& TheType,S
 #include <AIS_DisplayMode.hxx>
 #include <TopTools_ListOfShape.hxx>
 #include <BRepOffsetAPI_MakeThickSolid.hxx>
-#include <BRepOffset.hxx>
 
 //==============================================================================
 //  VIEWER OBJECT MANAGEMENT GLOBAL VARIABLES
diff --git a/tests/bugs/modalg_7/bug28968 b/tests/bugs/modalg_7/bug28968
new file mode 100644 (file)
index 0000000..fd12499
--- /dev/null
@@ -0,0 +1,46 @@
+puts "# ===================================================================="
+puts "# 0028968: Incorrect offset for the faces with singularities "
+puts "# ===================================================================="
+puts ""
+puts "# This test checks that offset does not fail and produces valid shape with"
+puts "# reasonable tolerance; however the real check for the problem is to be"
+puts "# made visually using generated images that should have no loops"
+puts "# (see images attached to Mantis issue)"
+puts ""
+
+set models {
+bug28968_HA-3828b-31.brep
+bug28968_HA-3781-31.brep
+bug28968_HA-3781-25.brep
+bug28968_HA-3781-01.brep
+bug28968_HA-3623g-31.brep
+bug28968_HA-3623g-22.brep
+bug28968_HA-3623c-20.brep
+bug28968_HA-3623c-19.brep
+bug28968_HA-3623c-15.brep
+bug28968_HA-3623b-31.brep
+bug28968_HA-3623b-22.brep
+bug28968_HA-3623a-28.brep
+bug28968_HA-3623a-27.brep
+bug28968_HA-3623a-26.brep
+bug28968_HA-3623a-17.brep
+}
+
+set i 0
+foreach file $models {
+  incr i
+  restore [locate_data_file $file] s$i
+
+  foreach command {offsetshapesimple} {
+    catch {$command res$i s$i 20. 0.01}
+    checkmaxtol res$i -min_tol 0.002
+    checkshape res$i
+
+    smallview
+    donly s$i res$i
+    fit
+
+    xwd "${imagedir}/${casename}_${command}_${i}_[file rootname $file].png" 
+#    checkview -2d smallview -display face$i -display res$i -screenshot -path $savepath
+  }
+}
index 4e0f1aa..98c8d1b 100644 (file)
@@ -5,4 +5,4 @@ set OffsetValue 20.0
 
 # Reference data.
 set ExpectedMass 2.96921e+006
-set ExpectedMaxTol 1.02
\ No newline at end of file
+set ExpectedMaxTol 0.683
index d93bb44..0cb386d 100644 (file)
@@ -5,4 +5,4 @@ set OffsetValue 80.0
 
 # Reference data.
 set ExpectedMass 2.94956e+006
-set ExpectedMaxTol 4.06
\ No newline at end of file
+set ExpectedMaxTol 2.76
\ No newline at end of file
diff --git a/tests/offset/simple/F01 b/tests/offset/simple/F01
new file mode 100644 (file)
index 0000000..a32cadb
--- /dev/null
@@ -0,0 +1,11 @@
+# Test data:
+puts "USER GUID: HA-3623a"
+
+restore [locate_data_file bug28968_HA-3623a-plate.brep] s
+
+set OffsetValue 20.0
+set SingularTol 0.01
+
+# Reference data.
+set ExpectedMass 3.15463e+007
+set ExpectedMaxTol 11.945619
diff --git a/tests/offset/simple/F02 b/tests/offset/simple/F02
new file mode 100644 (file)
index 0000000..73fa229
--- /dev/null
@@ -0,0 +1,10 @@
+# Test data:
+puts "USER GUID: HA-3623b"
+
+restore [locate_data_file bug28968_HA-3623b-hull.brep] s
+
+set OffsetValue 20.0
+
+# Reference data.
+set ExpectedMass 5.21983e+007
+set ExpectedMaxTol 0.29
diff --git a/tests/offset/simple/F03 b/tests/offset/simple/F03
new file mode 100644 (file)
index 0000000..2ee6339
--- /dev/null
@@ -0,0 +1,11 @@
+# Test data:
+puts "USER GUID: HA-3623c"
+
+restore [locate_data_file bug28968_HA-3623c-hull.brep] s
+
+set OffsetValue 20.0
+set SingularTol 0.01
+
+# Reference data.
+set ExpectedMass 2.35078e+007
+set ExpectedMaxTol 0.139
diff --git a/tests/offset/simple/F04 b/tests/offset/simple/F04
new file mode 100644 (file)
index 0000000..6655195
--- /dev/null
@@ -0,0 +1,11 @@
+# Test data:
+puts "USER GUID: HA-3781"
+
+restore [locate_data_file bug28968_HA-3781-plate.brep] s
+
+set OffsetValue 20.0
+set SingularTol 0.01
+
+# Reference data.
+set ExpectedMass 2.7118e+007
+set ExpectedMaxTol 0.539
diff --git a/tests/offset/simple/F05 b/tests/offset/simple/F05
new file mode 100644 (file)
index 0000000..a556aad
--- /dev/null
@@ -0,0 +1,11 @@
+# Test data:
+puts "USER GUID: HA-3781"
+
+restore [locate_data_file bug26528_shell.brep] s
+
+set OffsetValue -20.0
+#set SingularTol 0.01
+
+# Reference data.
+set ExpectedMass 6.29528e+006
+set ExpectedMaxTol 10.03
index fd3b5f7..5f8f7b3 100644 (file)
@@ -5,4 +5,7 @@ cpulimit 100
 # "B" letter 26577
 # "C" letter 26578
 # "D" letter 26587, 27907, 27908, 27909, 27910, 27911, 27912, 27913
-# "E" letter SPE 2016_Oct pack
\ No newline at end of file
+# "E" letter SPE 2016_Oct pack
+
+# default tolerance for detecting singularities
+set SingularTol 1.e-7
index 4bd90b9..ae6829d 100644 (file)
@@ -1,5 +1,5 @@
 # Compute offset.
-offsetshapesimple result s $OffsetValue
+offsetshapesimple result s $OffsetValue $SingularTol
 
 # 1% relative tolerance
 set TolRel 1.0e-2