0027729: UnifySameDomain: allow the user to specify linear and angular tolerances
authormsv <msv@opencascade.com>
Fri, 29 Jul 2016 15:23:57 +0000 (18:23 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 18 Aug 2016 08:19:15 +0000 (11:19 +0300)
- New methods SetLinearTolerance and SetAngularTolerance have been added in the class ShapeUpgrade_UnifySameDomain.
- The algorithm has been modified to consider these tolerances when checking if two faces are same domain.
- The draw command unifysamedomain has been changed to accept new parameters.
- The internal method MergeSeq has been changed to avoid exception connected with access to unknown key in the data map.

Create test case

Small correction of test case for issue CR27729

src/SWDRAW/SWDRAW_ShapeUpgrade.cxx
src/ShapeUpgrade/ShapeUpgrade_UnifySameDomain.cxx
src/ShapeUpgrade/ShapeUpgrade_UnifySameDomain.hxx
tests/bugs/heal/bug27729 [new file with mode: 0644]

index 45c39fd7e109e90db7bcf4796797b0d6f2485ee0..4735f8fc16d5f3235f4d8c26a5309985c2f1b77d 100644 (file)
@@ -1284,14 +1284,16 @@ static ShapeUpgrade_UnifySameDomain& Unifier() {
 //=======================================================================
 static Standard_Integer unifysamedom(Draw_Interpretor& di, Standard_Integer n, const char** a)
 {
-  if (n < 3 || n > 6)
+  if (n < 3)
   {
-    di << "Use unifysamedom result shape [-f] [-e] [+b] [-i]\n";
+    di << "Use unifysamedom result shape [-f] [-e] [+b] [-i] [-t val] [-a val]\n";
     di << "options:\n";
-    di << "[-f] to switch off 'unify-faces' mode \n";
-    di << "[-e] to switch off 'unify-edges' mode\n";
-    di << "[+b] to switch on 'concat bspline' mode\n";
-    di << "[+i] to switch on 'allow internal edges' mode\n";
+    di << "-f to switch off 'unify-faces' mode \n";
+    di << "-e to switch off 'unify-edges' mode\n";
+    di << "+b to switch on 'concat bspline' mode\n";
+    di << "+i to switch on 'allow internal edges' mode\n";
+    di << "-t val to set linear tolerance\n";
+    di << "-a val to set angular tolerance\n";
     di << "'unify-faces' and 'unify-edges' modes are switched on by default";
     return 1;
   }
@@ -1305,6 +1307,8 @@ static Standard_Integer unifysamedom(Draw_Interpretor& di, Standard_Integer n, c
   Standard_Boolean anUEdges = Standard_True;
   Standard_Boolean anConBS = Standard_False;
   Standard_Boolean isAllowInternal = Standard_False;
+  Standard_Real aLinTol = Precision::Confusion();
+  Standard_Real aAngTol = Precision::Angular();
 
   if (n > 3)
     for ( int i = 3; i < n; i++ ) 
@@ -1317,10 +1321,24 @@ static Standard_Integer unifysamedom(Draw_Interpretor& di, Standard_Integer n, c
         anConBS = Standard_True;
       else if (!strcmp(a[i], "+i"))
         isAllowInternal = Standard_True;
+      else if (!strcmp(a[i], "-t") || !strcmp(a[i], "-a"))
+      {
+        if (++i < n)
+        {
+          (a[i-1][1] == 't' ? aLinTol : aAngTol) = Draw::Atof(a[i]);
+        }
+        else
+        {
+          di << "value expected after " << a[i-1];
+          return 1;
+        }
+      }
     }
 
   Unifier().Initialize(aShape, anUEdges, anUFaces, anConBS);
   Unifier().AllowInternalEdges(isAllowInternal);
+  Unifier().SetLinearTolerance(aLinTol);
+  Unifier().SetAngularTolerance(aAngTol);
   Unifier().Build();
   TopoDS_Shape Result = Unifier().Shape();
 
@@ -1556,7 +1574,7 @@ Standard_Integer reshape(Draw_Interpretor& di,
   theCommands.Add ("removeloc","result shape",__FILE__,removeloc,g);
   
   theCommands.Add ("unifysamedom",
-                   "unifysamedom result shape [-f] [-e] [+b]", __FILE__,unifysamedom,g);
+                   "unifysamedom result shape [-f] [-e] [+b] [-i] [-t val] [-a val]", __FILE__,unifysamedom,g);
   
   theCommands.Add ("unifysamedomgen",
                    "unifysamedomgen newshape oldshape : get new shape generated "
index 776b55d3a9456ed0ef30af17bff59a4cdaa4b535..014d20c39323465eedebb07d31fe1a45942d693d 100644 (file)
@@ -306,7 +306,9 @@ static Handle(Geom_Surface) ClearRts(const Handle(Geom_Surface)& aSurface)
 //purpose  : 
 //=======================================================================
 static Standard_Boolean IsSameDomain(const TopoDS_Face& aFace,
-                                     const TopoDS_Face& aCheckedFace)
+                                     const TopoDS_Face& aCheckedFace,
+                                     const Standard_Real theLinTol,
+                                     const Standard_Real theAngTol)
 {
   //checking the same handles
   TopLoc_Location L1, L2;
@@ -318,9 +320,6 @@ static Standard_Boolean IsSameDomain(const TopoDS_Face& aFace,
   if (S1 == S2 && L1 == L2)
     return Standard_True;
 
-  // planar and cylindrical cases (IMP 20052)
-  Standard_Real aPrec = Precision::Confusion();
-
   S1 = BRep_Tool::Surface(aFace);
   S2 = BRep_Tool::Surface(aCheckedFace);
 
@@ -333,6 +332,22 @@ static Standard_Boolean IsSameDomain(const TopoDS_Face& aFace,
   //if (!aGOFS1.IsNull()) S1 = aGOFS1->BasisSurface();
   //if (!aGOFS2.IsNull()) S2 = aGOFS2->BasisSurface();
 
+  // case of two planar surfaces:
+  // all kinds of surfaces checked, including b-spline and bezier
+  GeomLib_IsPlanarSurface aPlanarityChecker1(S1, theLinTol);
+  if (aPlanarityChecker1.IsPlanar()) {
+    GeomLib_IsPlanarSurface aPlanarityChecker2(S2, theLinTol);
+    if (aPlanarityChecker2.IsPlanar()) {
+      gp_Pln aPln1 = aPlanarityChecker1.Plan();
+      gp_Pln aPln2 = aPlanarityChecker2.Plan();
+
+      if (aPln1.Position().Direction().IsParallel(aPln2.Position().Direction(), theAngTol) &&
+        aPln1.Distance(aPln2) < theLinTol) {
+        return Standard_True;
+      }
+    }
+  }
+
   // case of two elementary surfaces: use OCCT tool
   // elementary surfaces: ConicalSurface, CylindricalSurface,
   //                      Plane, SphericalSurface and ToroidalSurface
@@ -346,7 +361,7 @@ static Standard_Boolean IsSameDomain(const TopoDS_Face& aFace,
     Handle(BRepTopAdaptor_TopolTool) aTT2 = new BRepTopAdaptor_TopolTool();
 
     try {
-      IntPatch_ImpImpIntersection anIIInt (aGA1, aTT1, aGA2, aTT2, aPrec, aPrec);
+      IntPatch_ImpImpIntersection anIIInt(aGA1, aTT1, aGA2, aTT2, theLinTol, theLinTol);
       if (!anIIInt.IsDone() || anIIInt.IsEmpty())
         return Standard_False;
 
@@ -357,22 +372,6 @@ static Standard_Boolean IsSameDomain(const TopoDS_Face& aFace,
     }
   }
 
-  // case of two planar surfaces:
-  // all kinds of surfaces checked, including b-spline and bezier
-  GeomLib_IsPlanarSurface aPlanarityChecker1 (S1, aPrec);
-  if (aPlanarityChecker1.IsPlanar()) {
-    GeomLib_IsPlanarSurface aPlanarityChecker2 (S2, aPrec);
-    if (aPlanarityChecker2.IsPlanar()) {
-      gp_Pln aPln1 = aPlanarityChecker1.Plan();
-      gp_Pln aPln2 = aPlanarityChecker2.Plan();
-
-      if (aPln1.Position().Direction().IsParallel(aPln2.Position().Direction(),Precision::Angular()) &&
-          aPln1.Distance(aPln2) < aPrec) {
-        return Standard_True;
-      }
-    }
-  }
-
   // case of two cylindrical surfaces, at least one of which is a swept surface
   // swept surfaces: SurfaceOfLinearExtrusion, SurfaceOfRevolution
   if ((S1->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)) ||
@@ -382,14 +381,14 @@ static Standard_Boolean IsSameDomain(const TopoDS_Face& aFace,
   {
     gp_Cylinder aCyl1, aCyl2;
     if (getCylinder(S1, aCyl1) && getCylinder(S2, aCyl2)) {
-      if (fabs(aCyl1.Radius() - aCyl2.Radius()) < aPrec) {
+      if (fabs(aCyl1.Radius() - aCyl2.Radius()) < theLinTol) {
         gp_Dir aDir1 = aCyl1.Position().Direction();
         gp_Dir aDir2 = aCyl2.Position().Direction();
         if (aDir1.IsParallel(aDir2, Precision::Angular())) {
           gp_Pnt aLoc1 = aCyl1.Location();
           gp_Pnt aLoc2 = aCyl2.Location();
           gp_Vec aVec12 (aLoc1, aLoc2);
-          if (aVec12.SquareMagnitude() < aPrec*aPrec ||
+          if (aVec12.SquareMagnitude() < theLinTol*theLinTol ||
               aVec12.IsParallel(aDir1, Precision::Angular())) {
             return Standard_True;
           }
@@ -1055,8 +1054,11 @@ static Standard_Boolean MergeSeq (TopTools_SequenceOfShape& SeqEdges,
       k++;
       for (Standard_Integer j = 2; j <= SeqOfSubsSeqOfEdges(i).SeqsEdges.Length(); j++)
       {
-        TopoDS_Shape OldEdge = NewEdges2OldEdges(SeqOfSubsSeqOfEdges(i).SeqsEdges(j));
-        theOldShapes.Bind(OldEdge, SeqOfSubsSeqOfEdges(i).UnionEdges);
+        const TopoDS_Shape& anOldEdge = SeqOfSubsSeqOfEdges(i).SeqsEdges(j);
+        const TopoDS_Shape* pOrigEdge = NewEdges2OldEdges.Seek(anOldEdge);
+        if (!pOrigEdge)
+          pOrigEdge = &anOldEdge;
+        theOldShapes.Bind(*pOrigEdge, SeqOfSubsSeqOfEdges(i).UnionEdges);
         theContext->Remove(SeqOfSubsSeqOfEdges(i).SeqsEdges(j));
       }
     }
@@ -1107,7 +1109,9 @@ static void CheckSharedVertices(const TopTools_SequenceOfShape& theSeqEdges,
 //=======================================================================
 
 ShapeUpgrade_UnifySameDomain::ShapeUpgrade_UnifySameDomain()
-  : myUnifyFaces (Standard_True),
+  : myLinTol(Precision::Confusion()),
+    myAngTol(Precision::Angular()),
+    myUnifyFaces(Standard_True),
     myUnifyEdges (Standard_True),
     myConcatBSplines (Standard_False),
     myAllowInternal (Standard_False)
@@ -1125,7 +1129,9 @@ ShapeUpgrade_UnifySameDomain::ShapeUpgrade_UnifySameDomain(const TopoDS_Shape& a
                                                            const Standard_Boolean UnifyFaces,
                                                            const Standard_Boolean ConcatBSplines)
   : myInitShape (aShape),
-    myUnifyFaces (UnifyFaces),
+    myLinTol(Precision::Confusion()),
+    myAngTol(Precision::Angular()),
+    myUnifyFaces(UnifyFaces),
     myUnifyEdges (UnifyEdges),
     myConcatBSplines (ConcatBSplines),
     myAllowInternal (Standard_False),
@@ -1297,7 +1303,7 @@ void ShapeUpgrade_UnifySameDomain::IntUnifyFaces(const TopoDS_Shape& theInpShape
         if (IsCheckSharedEdgeOri && !CheckSharedEdgeOri(aFace, anCheckedFace, edge) )
           continue;
 
-        if (IsSameDomain(aFace,anCheckedFace)) {
+        if (IsSameDomain(aFace,anCheckedFace, myLinTol, myAngTol)) {
 
           // hotfix for 27271: prevent merging along periodic direction.
           if (IsLikeSeam(edge, aFace, aBaseSurface))
index de185b65ce032b1305193e41b4ac51ab3a600852..8286e9215d6843c8561f17aab658cdb7b4271bc1 100644 (file)
@@ -62,7 +62,19 @@ public:
   //! topology. Without this flag merging through multi connected edge
   //! is forbidden. Default value is false.
   Standard_EXPORT void AllowInternalEdges (const Standard_Boolean theValue);
-  
+
+  //! Sets the linear tolerance. Default value is Precision::Confusion().
+  void SetLinearTolerance(const Standard_Real theValue)
+  {
+    myLinTol = theValue;
+  }
+
+  //! Sets the angular tolerance. Default value is Precision::Angular().
+  void SetAngularTolerance(const Standard_Real theValue)
+  {
+    myAngTol = theValue;
+  }
+
   //! Builds the resulting shape
   Standard_EXPORT void Build();
   
@@ -100,6 +112,8 @@ private:
                      Standard_Boolean IsCheckSharedEdgeOri);
 
   TopoDS_Shape myInitShape;
+  Standard_Real myLinTol;
+  Standard_Real myAngTol;
   Standard_Boolean myUnifyFaces;
   Standard_Boolean myUnifyEdges;
   Standard_Boolean myConcatBSplines;
diff --git a/tests/bugs/heal/bug27729 b/tests/bugs/heal/bug27729
new file mode 100644 (file)
index 0000000..ea65fa6
--- /dev/null
@@ -0,0 +1,18 @@
+puts "========"
+puts "OCC27729"
+puts "========"
+puts ""
+#######################################################################
+# UnifySameDomain: allow the user to specify linear and angular tolerances
+#######################################################################
+
+restore [locate_data_file bug27729_a_1275.brep] a
+
+unifysamedom r a -t 0.1 -a 0.08
+
+regexp {FACE *: *(\d*)} [nbshapes r] full nbfaces
+if {$nbfaces > 1000} {
+  puts "Error: number of faces in the result is too large"
+}
+
+checkview -display r -2d -path ${imagedir}/${test_image}.png
\ No newline at end of file