0024923: BRepMesh_CircleTool produces bad circles
authordrazmyslovich <razmyslovich@volumegraphics.com>
Thu, 30 Apr 2015 13:41:54 +0000 (16:41 +0300)
committerbugmaster <bugmaster@opencascade.com>
Wed, 6 May 2015 12:02:50 +0000 (15:02 +0300)
Calculate radius of circumcircle as maximum difference between its center and vertices or reference triangle.
Draw test command OCC25547 has been implemented.
Small optimizations for speed.

Update of test-cases according to the new behaviour

Update of test-cases in group mesh

src/BRepMesh/BRepMesh_CircleTool.cxx
src/BRepMesh/BRepMesh_CircleTool.hxx
src/QABugs/QABugs_19.cxx
tests/bugs/mesh/bug24923 [new file with mode: 0644]
tests/bugs/mesh/bug25364
tests/bugs/mesh/bug25519
tests/bugs/moddata_1/bug22759
tests/mesh/data/standard/B3

index b1fc784..5697216 100644 (file)
@@ -105,47 +105,73 @@ void BRepMesh_CircleTool::Bind(const Standard_Integer theIndex,
 }
 
 //=======================================================================
-//function : Bind
+//function : MakeCircle
 //purpose  : 
 //=======================================================================
-Standard_Boolean BRepMesh_CircleTool::Bind(const Standard_Integer theIndex,
-                                           const gp_XY&           thePoint1,
-                                           const gp_XY&           thePoint2,
-                                           const gp_XY&           thePoint3)
+Standard_Boolean BRepMesh_CircleTool::MakeCircle(const gp_XY&   thePoint1,
+                                                 const gp_XY&   thePoint2,
+                                                 const gp_XY&   thePoint3,
+                                                 gp_XY&         theLocation,
+                                                 Standard_Real& theRadius)
 {
-  const Standard_Real aPrecision   = Precision::PConfusion();
-  const Standard_Real aSqPrecision = aPrecision * aPrecision;
+  static const Standard_Real aPrecision   = Precision::PConfusion();
+  static const Standard_Real aSqPrecision = aPrecision * aPrecision;
 
-  const gp_XY aPoints[3] = { thePoint1, thePoint2, thePoint3 };
+  if ((thePoint1 - thePoint3).SquareModulus() < aSqPrecision)
+    return Standard_False;
 
-  gp_XY aNorm[3];
-  gp_XY aMidPnt[3];
-  for (Standard_Integer i = 0; i < 3; ++i)
-  {
-    const gp_XY& aPnt1 = aPoints[i];
-    const gp_XY& aPnt2 = aPoints[(i + 1) % 3];
+  gp_XY aLink1(thePoint2 - thePoint1);
+  if (aLink1.SquareModulus() < aSqPrecision)
+    return Standard_False;
 
-    aMidPnt[i] = (aPnt1 + aPnt2) / 2.;
+  gp_XY aLink2(thePoint3 - thePoint2);
+  if (aLink2.SquareModulus() < aSqPrecision)
+    return Standard_False;
+
+  gp_XY aMidPnt1 = (thePoint1 + thePoint2) / 2.;
+  gp_XY aNorm1   = gp_XY(aLink1.Y(), -aLink1.X());
+  aNorm1.Add(aMidPnt1);
 
-    gp_XY aLink(aPnt2 - aPnt1);
-    if (aLink.SquareModulus() < aSqPrecision)
-      return Standard_False;
+  if (aLink2.SquareModulus() < aSqPrecision)
+    return Standard_False;
 
-    aNorm[i] = gp_XY(aLink.Y(), -aLink.X());
-    aNorm[i].Add(aMidPnt[i]);
-  }
+  gp_XY aMidPnt2 = (thePoint2 + thePoint3) / 2.;
+  gp_XY aNorm2   = gp_XY(aLink2.Y(), -aLink2.X());
+  aNorm2.Add(aMidPnt2);
 
   gp_XY aIntPnt;
   Standard_Real aParam[2];
   BRepMesh_GeomTool::IntFlag aIntFlag = 
-    BRepMesh_GeomTool::IntLinLin(aMidPnt[0], aNorm[0],
-      aMidPnt[1], aNorm[1], aIntPnt, aParam);
+    BRepMesh_GeomTool::IntLinLin(aMidPnt1, aNorm1,
+      aMidPnt2, aNorm2, aIntPnt, aParam);
 
   if (aIntFlag != BRepMesh_GeomTool::Cross)
     return Standard_False;
 
-  Standard_Real aRadius = (aPoints[0] - aIntPnt).Modulus();
-  bind(theIndex, aIntPnt, aRadius);
+  theLocation = aIntPnt;
+
+  theRadius = Sqrt(Max(Max((thePoint1 - aIntPnt).SquareModulus(), 
+                           (thePoint2 - aIntPnt).SquareModulus()),
+                           (thePoint3 - aIntPnt).SquareModulus())) + aPrecision;
+
+  return Standard_True;
+}
+
+//=======================================================================
+//function : Bind
+//purpose  : 
+//=======================================================================
+Standard_Boolean BRepMesh_CircleTool::Bind(const Standard_Integer theIndex,
+                                           const gp_XY&           thePoint1,
+                                           const gp_XY&           thePoint2,
+                                           const gp_XY&           thePoint3)
+{
+  gp_XY aLocation;
+  Standard_Real aRadius;
+  if (!MakeCircle(thePoint1, thePoint2, thePoint3, aLocation, aRadius))
+    return Standard_False;
+
+  bind(theIndex, aLocation, aRadius);
   return Standard_True;
 }
 
index 394c2a3..c74a2a4 100644 (file)
@@ -87,6 +87,20 @@ public:
   Standard_EXPORT void Bind(const Standard_Integer theIndex,
                             const gp_Circ2d&       theCircle);
 
+  //! Computes circle on three points.
+  //! @param thePoint1 first point.
+  //! @param thePoint2 second point.
+  //! @param thePoint3 third point.
+  //! @param[out] theLocation center of computed circle.
+  //! @param[out] theRadius radius of computed circle.
+  //! @return FALSE in case of impossibility to build a circle 
+  //! on the given points, TRUE elsewhere.
+  Standard_EXPORT static Standard_Boolean MakeCircle(const gp_XY&   thePoint1,
+                                                     const gp_XY&   thePoint2,
+                                                     const gp_XY&   thePoint3,
+                                                     gp_XY&         theLocation,
+                                                     Standard_Real& theRadius);
+
   //! Computes circle on three points and bind it to the tool.
   //! @param theIndex index a circle should be bound with.
   //! @param thePoint1 first point.
index 0ffdf44..acff2f1 100755 (executable)
@@ -3602,6 +3602,94 @@ Standard_Integer xprojponf (Draw_Interpretor& di,
   return 0;
 }
 
+//=======================================================================
+//function : OCC25547
+//purpose  :
+//=======================================================================
+#include <BRepMesh_CircleTool.hxx>
+
+static Standard_Boolean inspect_point(const gp_XY&        thePoint,
+                                      const gp_XY&        theCenter,
+                                      const Standard_Real theRadius)
+{
+  static Standard_Real aPrecision   = Precision::PConfusion();
+  static Standard_Real aSqPrecision = aPrecision * aPrecision;
+  const gp_XY aDistVec = thePoint - theCenter;
+  if (aDistVec.SquareModulus() - (theRadius * theRadius) < aSqPrecision)
+    return Standard_True;
+  else
+    return Standard_False;
+}
+
+static Standard_Integer OCC24923(
+  Draw_Interpretor& theDI, 
+  Standard_Integer  argc, 
+  const char **     argv)
+{
+  srand(static_cast<unsigned int>(time(NULL)));
+
+  const Standard_Real    aMaxDeviation = (argc > 1) ? Draw::Atof(argv[1]) : 0.01;
+  const Standard_Integer aPointsNb     = 10000000;
+  const Standard_Real    aMinAngle     = 5 * M_PI / 180.;
+  static Standard_Real   aSqPrecision  = Precision::PConfusion() * Precision::PConfusion();
+
+  Standard_Integer aFailedNb = 0;
+  for (Standard_Integer i = 0; i < aPointsNb; ++i)
+  {
+    gp_XY p[3];
+    for (Standard_Integer j = 0; j < 3; ++j)
+      p[j].SetCoord(((Standard_Real)rand())/RAND_MAX, ((Standard_Real)rand())/RAND_MAX);
+
+    // Check that points do not compose degenerated triangle.
+    gp_XY aVec1 = p[1] - p[0];
+    gp_XY aVec2 = p[2] - p[0];
+    if (aVec1.SquareModulus() > aSqPrecision && 
+        aVec2.SquareModulus() > aSqPrecision &&
+        (aVec1 ^ aVec2) > aMinAngle)
+    {
+      gp_XY aCenter;
+      Standard_Real aRadius;
+      if (BRepMesh_CircleTool::MakeCircle(p[0], p[1], p[2], aCenter, aRadius))
+      {
+        if (!inspect_point(p[0], aCenter, aRadius) || 
+            !inspect_point(p[1], aCenter, aRadius) || 
+            !inspect_point(p[2], aCenter, aRadius))
+        {
+         /* theDI << "Missed: " <<
+            "p1=(" << p1.X() << ", " << p1.Y() << "), " <<
+            "p2=(" << p2.X() << ", " << p2.Y() << "), " <<
+            "p3=(" << p3.X() << ", " << p3.Y() << "), " <<
+            "c=(" << aCenter.X() << ", " << aCenter.Y() << "), " <<
+            "r=" << aRadius << "\n";*/
+            
+          ++aFailedNb;
+        }
+
+        continue;
+      }
+    }
+
+    // Ensure that aPointsNb suitable for tests are generated
+    --i;
+  }
+
+  const Standard_Real aDeviation = 
+    1. - (Standard_Real)(aPointsNb - aFailedNb) / (Standard_Real)aPointsNb;
+
+  theDI << "Number of failed cases: " << aFailedNb << " (Total " << aPointsNb << ")\n";
+  if (aDeviation > aMaxDeviation)
+  {
+    theDI << "Failed. Number of incorrect results is too huge: " << 
+      aDeviation * 100 << "% (Max " << aMaxDeviation * 100 << "%)" << "\n";
+    return 1;
+  }
+
+  theDI << "Deviation of incorrect results is: " <<
+    aDeviation * 100 << "% (Max " << aMaxDeviation * 100 << "%)" << "\n";
+  theDI << "Test completed\n";
+  return 0;
+}
+
 void QABugs::Commands_19(Draw_Interpretor& theCommands) {
   const char *group = "QABugs";
 
@@ -3671,5 +3759,6 @@ void QABugs::Commands_19(Draw_Interpretor& theCommands) {
   theCommands.Add ("OCC25547", "OCC25547", __FILE__, OCC25547, group);
   theCommands.Add ("OCC24881", "OCC24881 shape", __FILE__, OCC24881, group);
   theCommands.Add ("xprojponf", "xprojponf p f", __FILE__, xprojponf, group);
+  theCommands.Add ("OCC24923", "OCC24923", __FILE__, OCC24923, group);
   return;
 }
diff --git a/tests/bugs/mesh/bug24923 b/tests/bugs/mesh/bug24923
new file mode 100644 (file)
index 0000000..8efe17e
--- /dev/null
@@ -0,0 +1,16 @@
+puts "========"
+puts "OCC24923"
+puts "========"
+puts ""
+############################################
+# BRepMesh_CircleTool produces bad circles
+############################################
+
+pload QAcommands
+
+set bug_info [OCC24923]
+set num_failed [string range [lindex $bug_info 12] 0 [expr {[string first "%" [lindex $bug_info 12]] - 1}]]
+set max_failed [string range [lindex $bug_info 14] 0 [expr {[string first "%" [lindex $bug_info 14]] - 1}]]
+if {$num_failed > $max_failed} {
+  puts "ERROR: OCC24923 is reproduced. Number of failed tests is too large ($num_failed > $max_failed)."
+}
index 5ee0f1f..7440fd3 100755 (executable)
@@ -64,12 +64,12 @@ puts "mem_wsetpeak_2=${mem_wsetpeak_2}"
 puts "mem_virt_2=${mem_virt_2}"
 puts "mem_heap_2=${mem_heap_2}"
 
-set mem_delta_private 180
+set mem_delta_private 200
 set mem_delta_swap 100
 set mem_delta_swappeak 250
-set mem_delta_wset 180
-set mem_delta_wsetpeak 180
-set mem_delta_virt 180
+set mem_delta_wset 200
+set mem_delta_wsetpeak 200
+set mem_delta_virt 200
 set mem_delta_heap 80
 
 if { [regexp {Debug mode} [dversion]] } {
index 9f54bf6..73501ff 100755 (executable)
@@ -22,7 +22,7 @@ regexp {deflection ([0-9.+e-]+)} ${trinfo_s} str defl_s
 
 set good_nbtri 2721
 set good_nbnod 1405
-set good_defl 0.048938765264496524
+set good_defl 0.044436924588798624
 
 set good_percent 5
 
index af641bd..e93a2c5 100755 (executable)
@@ -30,13 +30,13 @@ if { [array get env os_type] != "" } {
 }
 if { [string compare $os "windows"] != 0 } {
    puts "OS = Linux"
-   set good_tri  524278
-   set good_nod  265870
+   set good_tri  520414
+   set good_nod  263938
    set good_defl 0.0026800432954056617
 } else {
    puts "OS = Windows NT"
-   set good_tri  524278
-   set good_nod  265870
+   set good_tri  520414
+   set good_nod  263938
    set good_defl 0.0026800432954056617
 }
 
index d20ef3b..3d5d29e 100755 (executable)
@@ -1,10 +1,10 @@
 set TheFileName shading_012.brep
 ###set bug_withouttri "OCC22687"
 ###set nbwithouttri(All) 1
-if { [string compare $command "shading"] == 0 } {
-   set bug_freelinks "OCC23106"
-   set nbfree(All) 4
-} else {
-   set bug_freelinks "OCC25378"
-   set nbfree(All) 3
-}
+#if { [string compare $command "shading"] == 0 } {
+#   set bug_freelinks "OCC23106"
+#   set nbfree(All) 4
+#} else {
+#   set bug_freelinks "OCC25378"
+#   set nbfree(All) 3
+#}