diff --git a/src/BRepMesh/BRepMesh_CircleTool.cxx b/src/BRepMesh/BRepMesh_CircleTool.cxx index b1fc784396..5697216273 100644 --- a/src/BRepMesh/BRepMesh_CircleTool.cxx +++ b/src/BRepMesh/BRepMesh_CircleTool.cxx @@ -104,6 +104,59 @@ void BRepMesh_CircleTool::Bind(const Standard_Integer theIndex, bind(theIndex, aCoord, aRadius); } +//======================================================================= +//function : MakeCircle +//purpose : +//======================================================================= +Standard_Boolean BRepMesh_CircleTool::MakeCircle(const gp_XY& thePoint1, + const gp_XY& thePoint2, + const gp_XY& thePoint3, + gp_XY& theLocation, + Standard_Real& theRadius) +{ + static const Standard_Real aPrecision = Precision::PConfusion(); + static const Standard_Real aSqPrecision = aPrecision * aPrecision; + + if ((thePoint1 - thePoint3).SquareModulus() < aSqPrecision) + return Standard_False; + + gp_XY aLink1(thePoint2 - thePoint1); + if (aLink1.SquareModulus() < aSqPrecision) + return Standard_False; + + 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); + + if (aLink2.SquareModulus() < aSqPrecision) + return Standard_False; + + 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(aMidPnt1, aNorm1, + aMidPnt2, aNorm2, aIntPnt, aParam); + + if (aIntFlag != BRepMesh_GeomTool::Cross) + return Standard_False; + + theLocation = aIntPnt; + + theRadius = Sqrt(Max(Max((thePoint1 - aIntPnt).SquareModulus(), + (thePoint2 - aIntPnt).SquareModulus()), + (thePoint3 - aIntPnt).SquareModulus())) + aPrecision; + + return Standard_True; +} + //======================================================================= //function : Bind //purpose : @@ -113,39 +166,12 @@ Standard_Boolean BRepMesh_CircleTool::Bind(const Standard_Integer theIndex, const gp_XY& thePoint2, const gp_XY& thePoint3) { - const Standard_Real aPrecision = Precision::PConfusion(); - const Standard_Real aSqPrecision = aPrecision * aPrecision; - - const gp_XY aPoints[3] = { thePoint1, thePoint2, thePoint3 }; - - 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]; - - aMidPnt[i] = (aPnt1 + aPnt2) / 2.; - - gp_XY aLink(aPnt2 - aPnt1); - if (aLink.SquareModulus() < aSqPrecision) - return Standard_False; - - aNorm[i] = gp_XY(aLink.Y(), -aLink.X()); - aNorm[i].Add(aMidPnt[i]); - } - - gp_XY aIntPnt; - Standard_Real aParam[2]; - BRepMesh_GeomTool::IntFlag aIntFlag = - BRepMesh_GeomTool::IntLinLin(aMidPnt[0], aNorm[0], - aMidPnt[1], aNorm[1], aIntPnt, aParam); - - if (aIntFlag != BRepMesh_GeomTool::Cross) + gp_XY aLocation; + Standard_Real aRadius; + if (!MakeCircle(thePoint1, thePoint2, thePoint3, aLocation, aRadius)) return Standard_False; - Standard_Real aRadius = (aPoints[0] - aIntPnt).Modulus(); - bind(theIndex, aIntPnt, aRadius); + bind(theIndex, aLocation, aRadius); return Standard_True; } diff --git a/src/BRepMesh/BRepMesh_CircleTool.hxx b/src/BRepMesh/BRepMesh_CircleTool.hxx index 394c2a37a9..c74a2a4fe6 100644 --- a/src/BRepMesh/BRepMesh_CircleTool.hxx +++ b/src/BRepMesh/BRepMesh_CircleTool.hxx @@ -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. diff --git a/src/QABugs/QABugs_19.cxx b/src/QABugs/QABugs_19.cxx index 0ffdf446d1..acff2f1eea 100755 --- a/src/QABugs/QABugs_19.cxx +++ b/src/QABugs/QABugs_19.cxx @@ -3602,6 +3602,94 @@ Standard_Integer xprojponf (Draw_Interpretor& di, return 0; } +//======================================================================= +//function : OCC25547 +//purpose : +//======================================================================= +#include + +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(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 index 0000000000..8efe17e809 --- /dev/null +++ b/tests/bugs/mesh/bug24923 @@ -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)." +} diff --git a/tests/bugs/mesh/bug25364 b/tests/bugs/mesh/bug25364 index 5ee0f1f831..7440fd3853 100755 --- a/tests/bugs/mesh/bug25364 +++ b/tests/bugs/mesh/bug25364 @@ -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]] } { diff --git a/tests/bugs/mesh/bug25519 b/tests/bugs/mesh/bug25519 index 9f54bf6e71..73501ff6bb 100755 --- a/tests/bugs/mesh/bug25519 +++ b/tests/bugs/mesh/bug25519 @@ -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 diff --git a/tests/bugs/moddata_1/bug22759 b/tests/bugs/moddata_1/bug22759 index af641bd28b..e93a2c52c8 100755 --- a/tests/bugs/moddata_1/bug22759 +++ b/tests/bugs/moddata_1/bug22759 @@ -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 } diff --git a/tests/mesh/data/standard/B3 b/tests/mesh/data/standard/B3 index d20ef3b0fa..3d5d29e413 100755 --- a/tests/mesh/data/standard/B3 +++ b/tests/mesh/data/standard/B3 @@ -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 +#}