0025410: Tool for extended check of validity of the curve on the surface
authornbv <nbv@opencascade.com>
Thu, 30 Oct 2014 11:26:16 +0000 (14:26 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 30 Oct 2014 11:27:29 +0000 (14:27 +0300)
Modifications:
1. class BOPTools_AlgoTools
1.1. method
 Standard_Boolean BOPTools_AlgoTools::ComputeTolerance
  (const Handle(Geom_Curve)& theCurve3D,
   const Handle(Geom2d_Curve)& theCurve2D,
   const Handle(Geom_Surface)& theSurf,
   const Standard_Real theFirst,
   const Standard_Real theLast,
   Standard_Real& theMaxDist,
   Standard_Real& theMaxPar)
  It computes the max distance between points taken from 3D and 2D curves by the same parameter

1.2. method
 Standard_Boolean BOPTools_AlgoTools::ComputeTolerance
  (const TopoDS_Face& theFace,
   const TopoDS_Edge& theEdge,
   Standard_Real& theMaxDist,
   Standard_Real& theParameter)
  Computes the valid value of the tolerance for the edge using the function above.

2.  Added possibility to check shape on the validity of the curves on the surfaces.
2.1. New status BOPAlgo_InvalidCurveOnSurface has been added to the enumeration BOPAlgo_CheckStatus
2.2. class BOPAlgo_ArgumentAnalyzer
 method
   void BOPAlgo_ArgumentAnalyzer::TestCurveOnSurface()
 It checks each edge/face pair in the shape using the method ComputeTolerance from BOPTools_AlgoTools and stores invalid pairs to myResults.
 Invalid pairs are those which contain the edge with tolerance value less then the value computed by the ComputeTolerance method.

2.3. class BOPAlgo_CheckResult
 Added new fields:
    myMaxDist1 : Real from Standard;
    myMaxDist2 : Real from Standard;
    myMaxPar1  : Real from Standard;
    myMaxPar2  : Real from Standard;
 and corresponding setters and getters.
 These fields are used to store the results of the TestCurveOnSurface() check.

3. Added new option to the bopargcheck command and two new commands.
class BOPTest_CheckCommands
3.1. command bopargcheck
 As it is using the BOPAlgo_ArgumentAnalyzer class to check the shapes
 it checks also the validity of the curves on the surfaces.
 The output for the invalid shapes is following:

Draw[]> bopargcheck b2 /ic #f
Made faulty shape: s1COnS_1 (MaxDist = 0.0013334343378738308, MaxPar = 0.02884285498274167)
Made faulty shape: s1COnS_2 (MaxDist = 0.0013334340648766174, MaxPar = 0.02884285497934707)
Made faulty shape: s1COnS_3 (MaxDist = 0.0013335086668628978, MaxPar = 1.4133051942712607)
Made faulty shape: s1COnS_4 (MaxDist = 0.0013335086525838983, MaxPar = 1.4133051942713901)
Faulties for FIRST  shape found : 4
---------------------------------
Shapes are not suppotrted by BOP: NO
Self-Intersections              : NO
Check for SI has been aborted   : NO
Too small edges                 : NO
Bad faces                       : NO
Too close vertices              : NO
Too close edges                 : NO
Shapes with Continuity C0       : NO
Invalid Curve on Surface        : YES  Cases(4)  Total shapes(8)

Faulties for SECOND  shape found : 0

 The compounds s1COnS_* contain pair of edge and face.
 MaxDist is maximal distance between points taken from 3D curve of the edge and 2D curve of that edge on the face.
 MaxPar is a parameter in which the MaxDist is reached.

 To disable this check it is necessary to use option /S (bopargcheck shape /S).

3.2. command xdistef
 Usage of the command:
   xdistef edge face
 It computes distance between points taken from 3D curve of the edge and 2D curve of that edge on the face.
 Example:
Draw[]> explode s1COnS_1
s1COnS_1_1 s1COnS_1_2
Draw[]> whatis s1COnS_1_1
s1COnS_1_1 is a shape EDGE FORWARD Modified Orientable
Draw[]> whatis s1COnS_1_2
s1COnS_1_2 is a shape FACE FORWARD Modified Orientable
Draw[]> xdistef s1COnS_1_1 s1COnS_1_2
Max Distance = 0.0013334343378738308; Parameter on curve = 0.02884285498274167

3.3. command checkcurveonsurf
 Usage of the command:
  checkcurveonsurf shape.
 It checks each edge/face pair in the shape using the method ComputeTolerance from BOPTools_AlgoTools.
Example:
Draw[]> checkcurveonsurf b2
Invalid curves on surface:
edge e_0 on face f_0 (max dist: 0.0013334343378738, parameter on curve: 0.0288428549827417)
edge e_1 on face f_0 (max dist: 0.0013334340648766, parameter on curve: 0.0288428549793471)
edge e_2 on face f_1 (max dist: 0.0013335086668629, parameter on curve: 1.4133051942712607)
edge e_3 on face f_1 (max dist: 0.0013335086525839, parameter on curve: 1.4133051942713901)

Sugestions to fix the shape:
explode b2 e;
settolerance b2_6 0.0013335086668629;
settolerance b2_7 0.0013334343378738;
settolerance b2_8 0.0013334340648766;
settolerance b2_10 0.0013335086525839;

The command gives suggestions to fix the shape by increasing tolerance values of the invalid edges.
In some cases the tolerance values suggested by the tool can be very large.
Such values should be used very carefully, because setting large tolerance values to the sub-shapes
of the shape can make it non valid (self-interfered) or lead to unexpected result when using
such shapes in some operations (boolean for example).

Test case for issue CR25410

src/BOPAlgo/BOPAlgo.cdl
src/BOPAlgo/BOPAlgo_ArgumentAnalyzer.cdl
src/BOPAlgo/BOPAlgo_ArgumentAnalyzer.cxx
src/BOPAlgo/BOPAlgo_ArgumentAnalyzer.lxx
src/BOPAlgo/BOPAlgo_CheckResult.cdl
src/BOPAlgo/BOPAlgo_CheckResult.cxx
src/BOPTest/BOPTest_CheckCommands.cxx
src/BOPTools/BOPTools_AlgoTools.cdl
src/BOPTools/BOPTools_AlgoTools_1.cxx
tests/bugs/modalg_5/bug25410 [new file with mode: 0755]

index 567bb83..f59c73f 100644 (file)
@@ -52,6 +52,7 @@ is
       IncompatibilityOfFace, 
       OperationAborted,
       GeomAbs_C0,
+      InvalidCurveOnSurface,
       NotValid
     end CheckStatus;
 
index 47fa9f4..0c15f28 100644 (file)
@@ -115,6 +115,13 @@ is
     ---Purpose: Returns (modifiable) mode that means
     --          checking of problem of continuity of the shape.
 
+    CurveOnSurfaceMode(me: in out) 
+    returns Boolean from Standard;
+    ---C++: return &
+    ---C++: inline
+    ---Purpose: Returns (modifiable) mode that means
+    --          checking of problem of invalid curve on surface.
+
     ---
     Perform(me: out);
     ---Purpose: performs analysis
@@ -154,6 +161,9 @@ is
     is protected;
 
     TestContinuity(me: out)
+    is protected; 
+     
+    TestCurveOnSurface(me: out) 
     is protected;
 
 --  TestMergeFace(me: out)
@@ -162,20 +172,20 @@ is
 
 fields
 
-    myShape1           : Shape     from TopoDS;
-    myShape2           : Shape     from TopoDS;
-    myStopOnFirst      : Boolean   from Standard;
-    myOperation        : Operation from BOPAlgo;
-    myArgumentTypeMode : Boolean   from Standard;
-    mySelfInterMode    : Boolean   from Standard;
-    mySmallEdgeMode    : Boolean   from Standard;
-    myRebuildFaceMode  : Boolean   from Standard;
-    myTangentMode      : Boolean   from Standard;
-    myMergeVertexMode  : Boolean   from Standard;
-    myMergeEdgeMode    : Boolean   from Standard;
-    myContinuityMode   : Boolean   from Standard;
-    myEmpty1,myEmpty2  : Boolean   from Standard; 
-    myResult      : ListOfCheckResult from BOPAlgo; 
-    
-    
+    myShape1             : Shape     from TopoDS;
+    myShape2             : Shape     from TopoDS;
+    myStopOnFirst        : Boolean   from Standard;
+    myOperation          : Operation from BOPAlgo;
+    myArgumentTypeMode   : Boolean   from Standard;
+    mySelfInterMode      : Boolean   from Standard;
+    mySmallEdgeMode      : Boolean   from Standard;
+    myRebuildFaceMode    : Boolean   from Standard;
+    myTangentMode        : Boolean   from Standard;
+    myMergeVertexMode    : Boolean   from Standard;
+    myMergeEdgeMode      : Boolean   from Standard;
+    myContinuityMode     : Boolean   from Standard; 
+    myCurveOnSurfaceMode : Boolean   from Standard; 
+    myEmpty1, myEmpty2   : Boolean   from Standard; 
+    myResult     : ListOfCheckResult from BOPAlgo; 
+        
 end ArgumentAnalyzer;
index 0ad3abc..c0ee0a0 100644 (file)
@@ -74,6 +74,7 @@ myTangentMode(Standard_False),
 myMergeVertexMode(Standard_False),
 myMergeEdgeMode(Standard_False),
 myContinuityMode(Standard_False),
+myCurveOnSurfaceMode(Standard_False),
 myEmpty1(Standard_False),
 myEmpty2(Standard_False)
 {
@@ -196,6 +197,11 @@ void BOPAlgo_ArgumentAnalyzer::Perform()
       if(!(!myResult.IsEmpty() && myStopOnFirst))
         TestContinuity();
     }
+
+    if(myCurveOnSurfaceMode) {
+      if(!(!myResult.IsEmpty() && myStopOnFirst))
+        TestCurveOnSurface();
+    }
   }
   catch(Standard_Failure) {
     BOPAlgo_CheckResult aResult;
@@ -816,3 +822,55 @@ void BOPAlgo_ArgumentAnalyzer::TestContinuity()
     }
   }
 }
+
+// ================================================================================
+// function: TestCurveOnSurface
+// purpose:
+// ================================================================================
+void BOPAlgo_ArgumentAnalyzer::TestCurveOnSurface()
+{
+  Standard_Integer i;
+  Standard_Real aT, aD, aTolE;
+  TopExp_Explorer aExpF, aExpE;
+  //
+  for(i = 0; i < 2; i++) {
+    const TopoDS_Shape& aS = (i == 0) ? myShape1 : myShape2;
+    if(aS.IsNull()) {
+      continue;
+    }
+    //
+    aExpF.Init(aS, TopAbs_FACE);
+    for (; aExpF.More(); aExpF.Next()) {
+      const TopoDS_Face& aF = *(TopoDS_Face*)&aExpF.Current();
+      //
+      aExpE.Init(aF, TopAbs_EDGE);
+      for (; aExpE.More(); aExpE.Next()) {
+        const TopoDS_Edge& aE = *(TopoDS_Edge*)&aExpE.Current();
+        //
+        if (BOPTools_AlgoTools::ComputeTolerance(aF, aE, aD, aT)) {
+          aTolE = BRep_Tool::Tolerance(aE);
+          if (aD > aTolE) {
+            BOPAlgo_CheckResult aResult;
+            aResult.SetCheckStatus(BOPAlgo_InvalidCurveOnSurface);
+            if(i == 0) {
+              aResult.SetShape1(myShape1);
+              aResult.AddFaultyShape1(aE);
+              aResult.AddFaultyShape1(aF);
+              aResult.SetMaxDistance1(aD);
+              aResult.SetMaxParameter1(aT);
+            }
+            else {
+              aResult.SetShape2(myShape2);
+              aResult.AddFaultyShape2(aE);
+              aResult.AddFaultyShape2(aF);
+              aResult.SetMaxDistance2(aD);
+              aResult.SetMaxParameter2(aT);
+            }
+            myResult.Append(aResult);
+          }
+        }
+      }
+    }
+  }
+}
+
index e248a05..d5102f0 100644 (file)
@@ -57,6 +57,10 @@ inline Standard_Boolean& BOPAlgo_ArgumentAnalyzer::ContinuityMode()
   return myContinuityMode;
 }
 
+inline Standard_Boolean& BOPAlgo_ArgumentAnalyzer::CurveOnSurfaceMode() 
+{
+  return myCurveOnSurfaceMode;
+}
 // inline Standard_Boolean& BOPAlgo_ArgumentAnalyzer::MergeFaceMode() 
 // {
 //   return myMergeFaceMode;
index c733ec9..541a91b 100644 (file)
@@ -39,7 +39,7 @@ is
     ---Purpose: sets ancestor shape (tool) for faulty sub-shapes
     
     AddFaultyShape2(me: in out; TheShape: Shape from TopoDS);
-    ---Purpose: adds faulty sub-shapes from tool to a list
+    ---Purpose: adds faulty sub-shapes from tool to a list 
     
     GetShape1(me)
     returns Shape from TopoDS;
@@ -66,7 +66,39 @@ is
     
     GetCheckStatus(me)
     returns CheckStatus from BOPAlgo;
-    ---Purpose: gets status of faulty
+    ---Purpose: gets status of faulty 
+     
+    SetMaxDistance1(me:out; 
+        theDist : Real from Standard); 
+    ---Purpose: Sets max distance for the first shape
+    SetMaxDistance2(me:out; 
+        theDist : Real from Standard); 
+    ---Purpose: Sets max distance for the second shape
+    SetMaxParameter1(me:out; 
+        thePar : Real from Standard); 
+    ---Purpose: Sets the parameter for the first shape
+    SetMaxParameter2(me:out; 
+        thePar : Real from Standard); 
+    ---Purpose: Sets the parameter for the second shape 
+     
+    GetMaxDistance1(me) 
+    returns Real from Standard; 
+    ---Purpose: Returns the distance for the first shape
+    GetMaxDistance2(me) 
+    returns Real from Standard; 
+    ---Purpose: Returns the distance for the second shape
+    GetMaxParameter1(me) 
+    returns Real from Standard; 
+    ---Purpose: Returns the parameter for the fircst shape
+    GetMaxParameter2(me) 
+    returns Real from Standard; 
+    ---Purpose: Returns the parameter for the second shape
   
 fields
 
@@ -74,6 +106,10 @@ fields
     myShape2 : Shape from TopoDS;
     myStatus : CheckStatus from BOPAlgo;
     myFaulty1 : ListOfShape from BOPCol;
-    myFaulty2 : ListOfShape from BOPCol;
+    myFaulty2 : ListOfShape from BOPCol; 
+    myMaxDist1 : Real from Standard;
+    myMaxDist2 : Real from Standard;
+    myMaxPar1  : Real from Standard;
+    myMaxPar2  : Real from Standard;
 
 end CheckResult;
index 2e0fd35..9a87b82 100644 (file)
 // function:  BOPAlgo_CheckResult()
 // purpose: 
 //=======================================================================
-BOPAlgo_CheckResult::BOPAlgo_CheckResult() : myStatus(BOPAlgo_CheckUnknown)
+BOPAlgo_CheckResult::BOPAlgo_CheckResult() 
+: 
+  myStatus(BOPAlgo_CheckUnknown),
+  myMaxDist1(0.),
+  myMaxDist2(0.),
+  myMaxPar1(0.),
+  myMaxPar2(0.)
 {
 }
 
@@ -72,3 +78,43 @@ BOPAlgo_CheckStatus BOPAlgo_CheckResult::GetCheckStatus() const
 {
   return myStatus;
 }
+
+void BOPAlgo_CheckResult::SetMaxDistance1(const Standard_Real theDist)
+{
+  myMaxDist1 = theDist;
+}
+
+void BOPAlgo_CheckResult::SetMaxDistance2(const Standard_Real theDist)
+{
+  myMaxDist2 = theDist;
+}
+
+void BOPAlgo_CheckResult::SetMaxParameter1(const Standard_Real thePar)
+{
+  myMaxPar1 = thePar;
+}
+
+void BOPAlgo_CheckResult::SetMaxParameter2(const Standard_Real thePar)
+{
+  myMaxPar2 = thePar;
+}
+
+Standard_Real BOPAlgo_CheckResult::GetMaxDistance1() const
+{
+  return myMaxDist1;
+}
+
+Standard_Real BOPAlgo_CheckResult::GetMaxDistance2() const
+{
+  return myMaxDist2;
+}
+
+Standard_Real BOPAlgo_CheckResult::GetMaxParameter1() const
+{
+  return myMaxPar1;
+}
+
+Standard_Real BOPAlgo_CheckResult::GetMaxParameter2() const
+{
+  return myMaxPar2;
+}
index c724cd5..6ff8ae4 100644 (file)
 
 #include <TCollection_AsciiString.hxx>
 
+#include <TopExp_Explorer.hxx>
+
+#include <TopTools_MapOfShape.hxx>
+#include <TopTools_ShapeMapHasher.hxx>
+
 #include <TopoDS_Shape.hxx>
 #include <TopoDS_Compound.hxx>
 #include <BRep_Builder.hxx>
@@ -37,6 +42,8 @@
 #include <BOPAlgo_ArgumentAnalyzer.hxx>
 #include <BOPAlgo_CheckResult.hxx>
 
+#include <BOPTools_AlgoTools.hxx>
+
 #include <BOPTest_Chronometer.hxx>
 //
 static 
@@ -44,10 +51,15 @@ static
                                const Standard_Integer,
                                const BOPCol_ListOfShape&,
                                Standard_Integer& ,
-                               Draw_Interpretor&);
+                               Draw_Interpretor&,
+                               Standard_Boolean bCurveOnSurf = Standard_False,
+                               Standard_Real aMaxDist = 0.,
+                               Standard_Real aMaxParameter = 0.);
 //
 static Standard_Integer bopcheck   (Draw_Interpretor&, Standard_Integer, const char** );
 static Standard_Integer bopargcheck(Draw_Interpretor&, Standard_Integer, const char** );
+static Standard_Integer xdistef(Draw_Interpretor&, Standard_Integer, const char** );
+static Standard_Integer checkcurveonsurf (Draw_Interpretor&, Standard_Integer, const char**);
 
 //=======================================================================
 //function : CheckCommands
@@ -69,6 +81,12 @@ void  BOPTest::CheckCommands(Draw_Interpretor& theCommands)
   theCommands.Add("bopargcheck" , 
                   "Use bopargcheck without parameters to get ",  
                   __FILE__, bopargcheck, g);
+  theCommands.Add ("xdistef" ,
+                   "Use xdistef edge face",
+                   __FILE__, xdistef, g);
+  theCommands.Add("checkcurveonsurf",
+                  "checkcurveonsurf shape",
+                  __FILE__, checkcurveonsurf, g);
 }
 //=======================================================================
 //class    : BOPTest_Interf
@@ -306,14 +324,14 @@ Standard_Integer bopcheck (Draw_Interpretor& di,
 //function : bopargcheck
 //purpose  : 
 //=======================================================================
-Standard_Integer bopargcheck (Draw_Interpretor& di, 
-                              Standard_Integer n,  
+Standard_Integer bopargcheck (Draw_Interpretor& di,
+                              Standard_Integer n,
                               const char** a )
 {
   if (n<2) {
     di << "\n";
     di << " Use >bopargcheck Shape1 [[Shape2] ";
-    di << "[-F/O/C/T/S/U] [/R|F|T|V|E|I|P]] [#BF]" << "\n" << "\n";
+    di << "[-F/O/C/T/S/U] [/R|F|T|V|E|I|P|C|S]] [#BF]" << "\n" << "\n";
     di << " -<Boolean Operation>" << "\n";
     di << " F (fuse)" << "\n";
     di << " O (common)" << "\n";
@@ -333,6 +351,7 @@ Standard_Integer bopargcheck (Draw_Interpretor& di,
     di << " I (disable self-interference test)" << "\n";
     di << " P (disable shape type test)" << "\n";
     di << " C (disable test for shape continuity)" << "\n";
+    di << " S (disable curve on surface check)" << "\n";
     di << " For example: \"bopargcheck s1 s2 /RI\" disables ";
     di << "small edge detection and self-intersection detection" << "\n";
     di << " default - all options are enabled" << "\n" << "\n";
@@ -416,11 +435,12 @@ Standard_Integer bopargcheck (Draw_Interpretor& di,
   aChecker.SetShape1(aS1);
 
   // set default options (always tested!) for single and couple shapes
-  aChecker.ArgumentTypeMode() = Standard_True;
-  aChecker.SelfInterMode()    = Standard_True;
-  aChecker.SmallEdgeMode()    = Standard_True;
-  aChecker.RebuildFaceMode()  = Standard_True;
-  aChecker.ContinuityMode()   = Standard_True;
+  aChecker.ArgumentTypeMode()   = Standard_True;
+  aChecker.SelfInterMode()      = Standard_True;
+  aChecker.SmallEdgeMode()      = Standard_True;
+  aChecker.RebuildFaceMode()    = Standard_True;
+  aChecker.ContinuityMode()     = Standard_True;
+  aChecker.CurveOnSurfaceMode() = Standard_True;
 
   // test & set options and operation for two shapes
   if(!aS22.IsNull()) {
@@ -488,6 +508,9 @@ Standard_Integer bopargcheck (Draw_Interpretor& di,
       else if(a[indxOP][ind] == 'C' || a[indxOP][ind] == 'c') {
         aChecker.ContinuityMode() = Standard_False;
       }
+      else if(a[indxOP][ind] == 'S' || a[indxOP][ind] == 's') {
+        aChecker.CurveOnSurfaceMode() = Standard_False;
+      }
       else {
         di << "Error: invalid test option(s)!" << "\n";
         di << "Type bopargcheck without arguments for more information" << "\n";
@@ -538,6 +561,7 @@ Standard_Integer bopargcheck (Draw_Interpretor& di,
       Standard_Integer S2_SelfIntAll = 0, S2_SmalEAll = 0, S2_BadFAll = 0, S2_BadVAll = 0, S2_BadEAll = 0;
       Standard_Integer S1_OpAb = 0, S2_OpAb = 0;
       Standard_Integer S1_C0 = 0, S2_C0 = 0, S1_C0All = 0, S2_C0All = 0;
+      Standard_Integer S1_COnS = 0, S2_COnS = 0, S1_COnSAll = 0, S2_COnSAll = 0;
       Standard_Boolean hasUnknown = Standard_False;
 
       TCollection_AsciiString aS1SIBaseName("s1si_");
@@ -546,12 +570,14 @@ Standard_Integer bopargcheck (Draw_Interpretor& di,
       TCollection_AsciiString aS1BVBaseName("s1bv_");
       TCollection_AsciiString aS1BEBaseName("s1be_");
       TCollection_AsciiString aS1C0BaseName("s1C0_");
+      TCollection_AsciiString aS1COnSBaseName("s1COnS_");
       TCollection_AsciiString aS2SIBaseName("s2si_");
       TCollection_AsciiString aS2SEBaseName("s2se_");
       TCollection_AsciiString aS2BFBaseName("s2bf_");
       TCollection_AsciiString aS2BVBaseName("s2bv_");
       TCollection_AsciiString aS2BEBaseName("s2be_");
       TCollection_AsciiString aS2C0BaseName("s2C0_");
+      TCollection_AsciiString aS2COnSBaseName("s2COnS_");
 
       for(; anIt.More(); anIt.Next()) {
         const BOPAlgo_CheckResult& aResult = anIt.Value();
@@ -656,6 +682,27 @@ Standard_Integer bopargcheck (Draw_Interpretor& di,
           }
         }
           break;
+        case BOPAlgo_InvalidCurveOnSurface: {
+          if(!aSS1.IsNull()) {
+            S1_COnS++;
+            if(isL1) {
+              Standard_Real aMaxDist = aResult.GetMaxDistance1();
+              Standard_Real aMaxParameter = aResult.GetMaxParameter1();
+              MakeShapeForFullOutput(aS1COnSBaseName, S1_COnS, aLS1, S1_COnSAll, di,
+                                     Standard_True, aMaxDist, aMaxParameter);
+            }
+          }
+          if(!aSS2.IsNull()) {
+            S2_COnS++;
+            if(isL2) {
+              Standard_Real aMaxDist = aResult.GetMaxDistance2();
+              Standard_Real aMaxParameter = aResult.GetMaxParameter2();
+              MakeShapeForFullOutput(aS2COnSBaseName, S2_COnS, aLS2, S2_COnSAll, di,
+                                     Standard_True, aMaxDist, aMaxParameter);
+            }
+          }
+        }
+          break;
         case BOPAlgo_OperationAborted: {
           if(!aSS1.IsNull()) S1_OpAb++;
           if(!aSS2.IsNull()) S2_OpAb++;
@@ -669,9 +716,9 @@ Standard_Integer bopargcheck (Draw_Interpretor& di,
         } // switch
       }// faulties
 
-      Standard_Integer FS1 = S1_SelfInt + S1_SmalE + S1_BadF + S1_BadV + S1_BadE + S1_OpAb + S1_C0;
+      Standard_Integer FS1 = S1_SelfInt + S1_SmalE + S1_BadF + S1_BadV + S1_BadE + S1_OpAb + S1_C0 + S1_COnS;
       FS1 += (S1_BadType != 0) ? 1 : 0;
-      Standard_Integer FS2 = S2_SelfInt + S2_SmalE + S2_BadF + S2_BadV + S2_BadE + S2_OpAb + S2_C0;
+      Standard_Integer FS2 = S2_SelfInt + S2_SmalE + S2_BadF + S2_BadV + S2_BadE + S2_OpAb + S2_C0 + S2_COnS;
       FS2 += (S2_BadType != 0) ? 1 : 0;
       
       // output for first shape
@@ -750,6 +797,17 @@ Standard_Integer bopargcheck (Draw_Interpretor& di,
           di << "  Cases(" << S1_C0 << ")  Total shapes(" << S1_C0All << ")" << "\n";
         else
           di << "\n";
+
+        Standard_CString CString17;
+        if (S1_COnS != 0)
+          CString17="YES";
+        else
+          CString17="NO";
+        di << "Invalid Curve on Surface        : " << CString17;
+        if(S1_COnS != 0)
+          di << "  Cases(" << S1_COnS << ")  Total shapes(" << S1_COnSAll << ")" << "\n";
+        else
+          di << "\n";
       }
 
       // output for second shape
@@ -831,6 +889,17 @@ Standard_Integer bopargcheck (Draw_Interpretor& di,
         else
           di << "\n";
 
+        Standard_CString CString18;
+        if (S2_COnS != 0)
+          CString18="YES";
+        else
+          CString18="NO";
+        di << "Invalid Curve on Surface        : " << CString18;
+        if(S2_COnS != 0)
+          di << "  Cases(" << S2_COnS << ")  Total shapes(" << S2_COnSAll << ")" << "\n";
+        else
+          di << "\n";
+
         // warning
         di << "\n";
         if(hasUnknown)
@@ -841,15 +910,182 @@ Standard_Integer bopargcheck (Draw_Interpretor& di,
 
   return 0;
 }
+
+//=======================================================================
+//function : xdistef
+//purpose  : 
+//=======================================================================
+Standard_Integer xdistef(Draw_Interpretor& di,
+                         Standard_Integer n,
+                         const char** a)
+{
+  if(n < 3) {
+    di << "Use efmaxdist edge face\n";
+    return 1;
+  }
+  //
+  const TopoDS_Shape aS1 = DBRep::Get(a[1]);
+  const TopoDS_Shape aS2 = DBRep::Get(a[2]);
+  //
+  if (aS1.IsNull() || aS2.IsNull()) {
+    di << "null shapes\n";
+    return 1;
+  }
+  //
+  if (aS1.ShapeType() != TopAbs_EDGE || 
+      aS2.ShapeType() != TopAbs_FACE) {
+    di << "type mismatch\n";
+    return 1;
+  }
+  //
+  Standard_Real aMaxDist = 0.0, aMaxPar = 0.0;
+  //
+  const TopoDS_Edge& anEdge = *(TopoDS_Edge*)&aS1;
+  const TopoDS_Face& aFace  = *(TopoDS_Face*)&aS2;
+  //
+  if(!BOPTools_AlgoTools::ComputeTolerance
+     (aFace, anEdge, aMaxDist, aMaxPar)) {
+    di << "Tolerance cannot be computed\n";
+    return 1;
+  }
+  //
+  di << "Max Distance = " << aMaxDist 
+     << "; Parameter on curve = " << aMaxPar << "\n";
+  //
+  return 0;
+}
+
+//=======================================================================
+//function : checkcurveonsurf
+//purpose  : 
+//=======================================================================
+Standard_Integer checkcurveonsurf(Draw_Interpretor& di,
+                                  Standard_Integer n, 
+                                  const char** a)
+{
+  if (n != 2) {
+    di << "use checkcurveonsurf shape\n";
+    return 1;
+  }
+  //
+  TopoDS_Shape aS =  DBRep::Get(a[1]);
+  if (aS.IsNull()) {
+    di << "null shape\n";
+    return 1;
+  }
+  //
+  Standard_Integer nE, nF, anECounter, aFCounter;
+  Standard_Real aT, aTolE, aD, aDMax;
+  TopExp_Explorer aExpF, aExpE;
+  char buf[200], aFName[10], anEName[10];
+  NCollection_DataMap<TopoDS_Shape, Standard_Real, TopTools_ShapeMapHasher> aDMETol;
+  BOPCol_DataMapOfShapeInteger aMSI;
+  //
+  anECounter = 0;
+  aFCounter  = 0;
+  //
+  aExpF.Init(aS, TopAbs_FACE);
+  for (; aExpF.More(); aExpF.Next()) {
+    const TopoDS_Face& aF = *(TopoDS_Face*)&aExpF.Current();
+    //
+    aExpE.Init(aF, TopAbs_EDGE);
+    for (; aExpE.More(); aExpE.Next()) {
+      const TopoDS_Edge& aE = *(TopoDS_Edge*)&aExpE.Current();
+      //
+      if (!BOPTools_AlgoTools::ComputeTolerance(aF, aE, aDMax, aT)) {
+        continue;
+      }
+      //
+      aTolE = BRep_Tool::Tolerance(aE);
+      if (aDMax < aTolE) {
+        continue;
+      }
+      //
+      if (aDMETol.IsBound(aE)) {
+        aD = aDMETol.Find(aE);
+        if (aDMax > aD) {
+          aDMETol.UnBind(aE);
+          aDMETol.Bind(aE, aDMax);
+        }
+      }
+      else {
+        aDMETol.Bind(aE, aDMax);
+      }
+      //
+      if (anECounter == 0) {
+        di << "Invalid curves on surface:\n";
+      }
+      //
+      if (aMSI.IsBound(aE)) {
+        nE = aMSI.Find(aE);
+      }
+      else {
+        nE = anECounter;
+        aMSI.Bind(aE, nE);
+        ++anECounter;
+      }
+      //
+      if (aMSI.IsBound(aF)) {
+        nF = aMSI.Find(aF);
+      } else {
+        nF = aFCounter;
+        aMSI.Bind(aF, nF);
+        ++aFCounter;
+      }
+      //
+      sprintf(anEName, "e_%d", nE);
+      sprintf(aFName , "f_%d", nF);
+      sprintf(buf, "edge %s on face %s (max dist: %3.16f, parameter on curve: %3.16f)\n",
+              anEName, aFName, aDMax, aT);
+      di << buf;
+      //
+      DBRep::Set(anEName, aE);
+      DBRep::Set(aFName , aF);
+    }
+  }
+  //
+  if (anECounter > 0) {
+    di << "\n\nSugestions to fix the shape:\n";
+    di << "explode " << a[1] << " e;\n";
+    //
+    TopTools_MapOfShape M;
+    aExpE.Init(aS, TopAbs_EDGE);
+    for (anECounter = 0; aExpE.More(); aExpE.Next()) {
+      const TopoDS_Shape& aE = aExpE.Current();
+      if (!M.Add(aE)) {
+        continue;
+      }
+      ++anECounter;
+      //
+      if (!aDMETol.IsBound(aE)) {
+        continue;
+      }
+      //
+      aTolE = aDMETol.Find(aE);
+      aTolE *= 1.001;
+      sprintf(buf, "settolerance %s_%d %3.16f;\n", a[1], anECounter, aTolE);
+      di << buf;
+    }
+  }
+  else {
+    di << "This shape seems to be OK.\n";
+  }
+  //
+  return 0;
+}
+
 //=======================================================================
 //function : MakeShapeForFullOutput
 //purpose  : 
 //=======================================================================
 void MakeShapeForFullOutput (const TCollection_AsciiString & aBaseName,
                              const Standard_Integer          aIndex,
-                             const BOPCol_ListOfShape &    aList,
+                             const BOPCol_ListOfShape &      aList,
                              Standard_Integer&               aCount,
-                             Draw_Interpretor&               di)
+                             Draw_Interpretor&               di,
+                             Standard_Boolean                bCurveOnSurf,
+                             Standard_Real                   aMaxDist,
+                             Standard_Real                   aMaxParameter)
 {
   TCollection_AsciiString aNum(aIndex);
   TCollection_AsciiString aName = aBaseName + aNum;
@@ -865,6 +1101,14 @@ void MakeShapeForFullOutput (const TCollection_AsciiString & aBaseName,
     BB.Add(cmp, aS);
     aCount++;
   }
-  di << "Made faulty shape: " << name << "\n";
+  di << "Made faulty shape: " << name;
+  //
+  if (bCurveOnSurf) {
+    di << " (MaxDist = " << aMaxDist 
+       << ", MaxPar = " << aMaxParameter << ")";
+  }
+  //
+  di << "\n";
+  //
   DBRep::Set(name, cmp);
 }
index 6425c57..923763a 100644 (file)
@@ -33,6 +33,9 @@ uses
     Wire from TopoDS, 
     Shell from TopoDS,  
     Solid from TopoDS, 
+    Curve from Geom,
+    Curve from Geom2d,
+    Surface from Geom,
     --  
     BaseAllocator from BOPCol,
     ListOfShape from BOPCol,  
@@ -290,44 +293,41 @@ is
             theRunParallel: Boolean from Standard=Standard_False);   
  
     ---Purpose:         
-    --- Provides valid values of tolerances for the shape <theS>         
-    --- <theTolMax> is max value of the tolerance that can be 
-    --- accepted for correction.  If real value of the tolerance 
-    --- will be greater than  <aTolMax>, the correction does not 
-    --- perform. 
-    ---
+    -- Provides valid values of tolerances for the shape <theS>         
+    -- <theTolMax> is max value of the tolerance that can be 
+    -- accepted for correction.  If real value of the tolerance 
+    -- will be greater than  <aTolMax>, the correction does not 
+    -- perform. 
     CorrectCurveOnSurface  (myclass;  
             theS: Shape  from  TopoDS; 
             theTolMax: Real from Standard =0.0001; 
             theRunParallel: Boolean from Standard=Standard_False);   
     ---Purpose:         
-    --- Provides valid values of tolerances for the shape <theS> 
-    --- in  terms of BRepCheck_InvalidCurveOnSurface.   
-    ---
+    -- Provides valid values of tolerances for the shape <theS> 
+    -- in  terms of BRepCheck_InvalidCurveOnSurface.   
     CorrectPointOnCurve    (myclass;  
             theS: Shape  from  TopoDS; 
             theTolMax: Real from Standard =0.0001; 
             theRunParallel: Boolean from Standard=Standard_False);   
     ---Purpose:         
-    --- Provides valid values of tolerances for the shape <theS> 
-    --- in  terms of BRepCheck_InvalidPointOnCurve.   
-    ---
-    --fields 
+    -- Provides valid values of tolerances for the shape <theS> 
+    -- in  terms of BRepCheck_InvalidPointOnCurve.   
  
-    --copy from BOPTools_AlgoTools.cdl
     MakeNewVertex  (myclass;  
             aP1 : Pnt  from  gp;  
             aTol: Real from Standard;
             aNewVertex:out Vertex from TopoDS); 
     ---Purpose: 
-    --- Make a vertex using 3D-point <aP1> and 3D-tolerance value <aTol>  
-    ---
+    -- Make a vertex using 3D-point <aP1> and 3D-tolerance value <aTol>  
     MakeNewVertex  (myclass;  
         aV1,aV2:   Vertex from TopoDS; 
         aNewVertex:out Vertex from TopoDS);                                                  
     ---Purpose: 
-    --- Make a vertex using couple of vertices  <aV1, aV2>     
-    ---
+    -- Make a vertex using couple of vertices  <aV1, aV2>     
     MakeNewVertex  (myclass;  
             aE1: Edge from TopoDS; 
             aP1: Real from Standard; 
@@ -335,25 +335,25 @@ is
             aP2: Real from Standard; 
             aNewVertex:out Vertex from TopoDS);                                      
     ---Purpose: 
-    --- Make a vertex in place of intersection between two edges 
-    --- <aE1, aE2> with parameters <aP1, aP2>     
-    ---
+    -- Make a vertex in place of intersection between two edges 
+    -- <aE1, aE2> with parameters <aP1, aP2>     
     MakeNewVertex  (myclass;  
             aE1: Edge from TopoDS; 
             aP1: Real from Standard; 
             aF2: Face from TopoDS; 
             aNewVertex:out Vertex from TopoDS);         
     ---Purpose: 
-    --- Make a vertex in place of intersection between the edge <aE1> 
-    --- with parameter <aP1> and the face <aF2> 
-    ---
+    -- Make a vertex in place of intersection between the edge <aE1> 
+    -- with parameter <aP1> and the face <aF2> 
     PointOnEdge    (myclass;   
             aEdge: Edge from TopoDS; 
             aPrm: Real from Standard; 
             aP:out Pnt  from  gp);
     ---Purpose: 
-    --- Compute a 3D-point on the edge <aEdge> at parameter <aPrm> 
-    ---
+    -- Compute a 3D-point on the edge <aEdge> at parameter <aPrm> 
     MakeSplitEdge  (myclass;  
             aE1: Edge from TopoDS; 
             aV1: Vertex from TopoDS;             
@@ -362,9 +362,9 @@ is
             aP2: Real from Standard; 
             aNewEdge:out Edge from TopoDS);          
     ---Purpose: 
-    --- Make the edge from base edge <aE1> and two vertices <aV1,aV2>  
-    --- at parameters <aP1,aP2>  
-    ---
+    -- Make the edge from base edge <aE1> and two vertices <aV1,aV2>  
+    -- at parameters <aP1,aP2>  
     MakeSectEdge   (myclass;  
             aIC: Curve  from IntTools; 
             aV1: Vertex from TopoDS;             
@@ -373,35 +373,34 @@ is
             aP2: Real from Standard; 
             aNewEdge:out Edge from TopoDS);             
     ---Purpose: 
-    --- Make the edge from 3D-Curve <aIC>  and two vertices <aV1,aV2>  
-    --- at parameters <aP1,aP2>  
-    ---
+    -- Make the edge from 3D-Curve <aIC>  and two vertices <aV1,aV2>  
+    -- at parameters <aP1,aP2>  
     UpdateVertex   (myclass;  
             aIC: Curve  from IntTools; 
             aT : Real from Standard;  
             aV : Vertex from TopoDS); 
     ---Purpose:   
-    --- Update the tolerance value for vertex  <aV> 
-    --- taking into account the fact that <aV> lays on   
-    --- the curve <aIC>   
-    ---
+    -- Update the tolerance value for vertex  <aV> 
+    -- taking into account the fact that <aV> lays on   
+    -- the curve <aIC>   
     UpdateVertex   (myclass;  
             aE : Edge from TopoDS;  
             aT : Real from Standard;  
             aV : Vertex from TopoDS);              
     ---Purpose:  
-    --- Update the tolerance value for vertex  <aV> 
-    --- taking into account the fact that <aV> lays on   
-    --- the edge <aE>   
-    ---
+    -- Update the tolerance value for vertex  <aV> 
+    -- taking into account the fact that <aV> lays on   
+    -- the edge <aE>   
     UpdateVertex   (myclass;  
             aVF : Vertex from TopoDS; 
             aVN : Vertex from TopoDS);         
     ---Purpose:  
-    --- Update the tolerance value for vertex  <aVN> 
-    --- taking into account the fact that <aVN> should   
-    --- cover tolerance zone of <aVF>    
-    ---
+    -- Update the tolerance value for vertex  <aVN> 
+    -- taking into account the fact that <aVN> should   
+    -- cover tolerance zone of <aVF>    
  
     CorrectRange   (myclass;  
             aE1:   Edge from TopoDS;    
@@ -409,18 +408,17 @@ is
             aSR:   Range from IntTools;                        
             aNewSR:out  Range from IntTools);  
     ---Purpose:  
-    --- Correct shrunk range <aSR> taking into account 3D-curve      
-    --- resolution and corresp. tolerances' values of <aE1>, <aE2>   
-    ---
+    -- Correct shrunk range <aSR> taking into account 3D-curve      
+    -- resolution and corresp. tolerances' values of <aE1>, <aE2>   
     CorrectRange   (myclass;  
             aE:   Edge from TopoDS;    
             aF:   Face from TopoDS;   
             aSR:  Range from IntTools;                        
             aNewSR:out  Range from IntTools); 
     ---Purpose:  
-    --- Correct shrunk range <aSR> taking into account 3D-curve      
-    --- resolution and corresp. tolerances' values of <aE>, <aF>
-    ---
+    -- Correct shrunk range <aSR> taking into account 3D-curve      
+    -- resolution and corresp. tolerances' values of <aE>, <aF>
  
     IsBlockInOnFace(myclass;   
             aShR  : Range from IntTools; 
@@ -429,29 +427,28 @@ is
             aContext:out Context from IntTools)
         returns Boolean from Standard;               
     ---Purpose:  
-    --- Returns TRUE if PaveBlock <aPB> lays on the face <aF>, i.e 
-    --- the <PB> is IN or ON in 2D of <aF> 
+    -- Returns TRUE if PaveBlock <aPB> lays on the face <aF>, i.e 
+    -- the <PB> is IN or ON in 2D of <aF> 
      
     IsMicroEdge(myclass; 
             theEdge    : Edge from TopoDS; 
             theContext : Context from IntTools)  
         returns Boolean from Standard; 
     ---Purpose: 
-    --- Checks if it is possible to compute shrunk range for the edge <aE>. 
-    ---  
+    -- Checks if it is possible to compute shrunk range for the edge <aE>. 
+    --  
  
     CorrectShapeTolerances (myclass;
             theS: Shape from TopoDS; 
             theRunParallel: Boolean from Standard=Standard_False);   
     ---Purpose: 
-    --- Corrects tolerance values of the sub-shapes of the shape <theS> if needed. 
-    ---
+    -- Corrects tolerance values of the sub-shapes of the shape <theS> if needed. 
  
     Dimension(myclass; 
             theS:Shape from TopoDS) 
         returns Integer from Standard;
     ---Purpose: 
-    --- Retutns dimension of the shape <theS>. 
+    -- Retutns dimension of the shape <theS>. 
      
     IsOpenShell(myclass; 
             theShell:Shell from TopoDS)  
@@ -461,6 +458,26 @@ is
     IsInvertedSolid(myclass; 
             theSolid:Solid from TopoDS)  
         returns Boolean from Standard;  
-    ---Purpose: Returns true if the solid <theSolid> is inverted 
+    ---Purpose: Returns true if the solid <theSolid> is inverted  
      
+    ComputeTolerance(myclass;
+        theCurve3D : Curve from Geom;
+        theCurve2D : Curve from Geom2d;
+        theSurf    : Surface from Geom;
+        theMaxDist : out Real from Standard; 
+        theMaxPar  : out Real from Standard)
+    returns Boolean from Standard; 
+    ---Purpose:  
+    -- Computes the max distance between points  
+    -- taken from 3D and 2D curves by the same parameter
+
+    ComputeTolerance(myclass;
+        theFace : Face from TopoDS;
+        theEdge : Edge from TopoDS;
+        theMaxDist : out Real from Standard; 
+        theMaxPar  : out Real from Standard)
+    returns Boolean from Standard;
+    ---Purpose:  
+    -- Computes the necessary value of the tolerance for the edge
+
 end AlgoTools;
index a494494..ade9bc9 100644 (file)
@@ -311,6 +311,118 @@ typedef BOPCol_TBBCnt
   <BOPTools_CETFunctor,
   BOPTools_VectorOfCET> BOPTools_CETCnt;
 //
+//
+//=======================================================================
+//class    : BOPTools_CheckCurveOnSurface
+//purpose  : it is used to check the curve on the surface
+//=======================================================================
+#include <math_GlobOptMin.hxx>
+#include <math_MultipleVarFunctionWithHessian.hxx>
+#include <math_Matrix.hxx>
+#include <Geom2d_TrimmedCurve.hxx>
+
+class BOPTools_CheckCurveOnSurface : 
+  public math_MultipleVarFunctionWithHessian
+{
+ public:
+  BOPTools_CheckCurveOnSurface(BOPTools_CheckCurveOnSurface&);
+  BOPTools_CheckCurveOnSurface(const Handle(Geom_Curve)& theC3D,
+                              const Handle(Geom2d_Curve)& theC2D,
+                              const Handle(Geom_Surface)& theSurf)
+    :
+      my3DCurve(theC3D),
+      my2DCurve(theC2D),
+      mySurf(theSurf)
+  {
+  }
+  //
+  virtual Standard_Integer NbVariables() const {
+    return 1;
+  }
+  //
+  virtual Standard_Boolean Value(const math_Vector& theX,
+                                 Standard_Real& theFVal) {
+    try {
+      const Standard_Real aPar = theX(1);
+      gp_Pnt aP1, aP2;
+      gp_Pnt2d aP2d;
+      my3DCurve->D0(aPar, aP1);
+      my2DCurve->D0(aPar, aP2d);
+      mySurf->D0(aP2d.X(), aP2d.Y(), aP2);
+      //
+      theFVal = -1.0*aP1.SquareDistance(aP2);
+    }
+    catch(...) {
+      return Standard_False;
+    }
+    //
+    return Standard_True;
+  }
+  //
+  virtual Standard_Integer GetStateNumber() {
+    return 0;
+  }
+  //
+  virtual Standard_Boolean Gradient(const math_Vector& theX,
+                                    math_Vector& theGrad) {
+    try {
+      const Standard_Real aPar = theX(1);
+      
+      gp_Pnt aP1, aP2;
+      gp_Vec aDC3D, aDSU, aDSV;
+      gp_Pnt2d aP2d;
+      gp_Vec2d aDC2D;
+      
+      my3DCurve->D1(aPar, aP1, aDC3D);
+      my2DCurve->D1(aPar, aP2d, aDC2D);
+      mySurf->D1(aP2d.X(), aP2d.Y(), aP2, aDSU, aDSV);
+      
+      aP1.SetXYZ(aP1.XYZ() - aP2.XYZ());
+      aP2.SetXYZ(aDC3D.XYZ() - aDC2D.X()*aDSU.XYZ() - aDC2D.Y()*aDSV.XYZ());
+      
+      theGrad(1) = -2.0*aP1.XYZ().Dot(aP2.XYZ());
+    }
+    catch(...) {
+      return Standard_False;
+    }
+    
+    return Standard_True;
+  }
+  //   
+  virtual Standard_Boolean Values(const math_Vector& theX,
+                                  Standard_Real& theVal,
+                                  math_Vector& theGrad) {
+    if(!Value(theX, theVal))
+      return Standard_False;
+    
+    if(!Gradient(theX, theGrad))
+      return Standard_False;
+    
+    return Standard_True;
+  }
+  //
+  virtual Standard_Boolean Values(const math_Vector& theX,
+                                  Standard_Real& theVal,
+                                  math_Vector& theGrad,
+                                  math_Matrix& theHessian) {
+    if(!Value(theX, theVal))
+      return Standard_False;
+    
+    if(!Gradient(theX, theGrad))
+      return Standard_False;
+    
+    theHessian(1,1) = theGrad(1);
+    
+    return Standard_True;
+  }
+  //
+ private:
+  Handle(Geom_Curve) my3DCurve;
+  Handle(Geom2d_Curve) my2DCurve;
+  Handle(Geom_Surface) mySurf;
+};
+//=======================================================================
+//
 //=======================================================================
 // Function : CorrectTolerances
 // purpose : 
@@ -1037,3 +1149,237 @@ void UpdateEdges(const TopoDS_Face& aF)
     }
   }
 }
+//=======================================================================
+// Function : MinComputing
+// purpose : 
+//=======================================================================
+static Standard_Boolean MinComputing( BOPTools_CheckCurveOnSurface& theFunction,
+                                      const Standard_Real theFirst,
+                                      const Standard_Real theLast,
+                                      const Standard_Real theEpsilon, //1.0e-3
+                                      Standard_Real & theBestValue,
+                                      Standard_Real & theBestParameter)
+{
+  //Standard_Real aPrevValue = theBestValue;
+  const Standard_Real aStepMin = 1.0e-2;
+  math_Vector aFirstV(1, 1), aLastV(1, 1), anOutputParam(1, 1);
+  aFirstV(1) = theFirst;
+  aLastV(1) = theLast;
+
+  math_GlobOptMin aFinder(&theFunction, aFirstV, aLastV);
+  aFinder.SetTol(aStepMin, theEpsilon);
+  aFinder.Perform();
+
+  const Standard_Integer aNbExtr = aFinder.NbExtrema();
+  for(Standard_Integer i = 1; i <= aNbExtr; i++)
+  {
+    Standard_Real aValue = 0.0;
+    aFinder.Points(i, anOutputParam);
+    theFunction.Value(anOutputParam, aValue);
+    
+    if(aValue < theBestValue)
+    {
+      theBestValue = aValue;
+      theBestParameter = anOutputParam(1);
+    }
+  }
+
+  return Standard_True;
+}
+
+//=======================================================================
+// Function : ComputeTolerance
+// purpose : 
+//=======================================================================
+Standard_Boolean BOPTools_AlgoTools::
+          ComputeTolerance( const Handle(Geom_Curve)& theCurve3D,
+                            const Handle(Geom2d_Curve)& theCurve2D,
+                            const Handle(Geom_Surface)& theSurf,
+                            Standard_Real& theMaxDist,
+                            Standard_Real& theMaxPar)
+{
+  if (theCurve3D.IsNull() ||
+      theCurve2D.IsNull() ||
+      theSurf.IsNull()) {
+    return Standard_False;
+  }
+
+  const Standard_Real anEpsilonRange = 1.0e-3, aMinDelta = 1.0e-5;
+
+  //
+  try {
+    Standard_Real aFirst = theCurve3D->FirstParameter(),
+                  aLast = theCurve3D->LastParameter();
+
+    BOPTools_CheckCurveOnSurface aFunc(theCurve3D, theCurve2D, theSurf);
+    //
+    math_Vector anOutputParam(1, 1);
+    anOutputParam(1) = theMaxPar = aFirst;
+    //
+    theMaxDist = 0.;
+    MinComputing(aFunc, aFirst, aLast, anEpsilonRange, theMaxDist, theMaxPar);
+
+    Standard_Integer aNbIteration = 100;
+    Standard_Boolean aStatus = Standard_True;
+    while((aNbIteration-- >= 0) && aStatus)
+    {
+      Standard_Real aValue = theMaxDist, aParam = theMaxPar;
+      Standard_Real aBP = theMaxPar - aMinDelta;
+      MinComputing(aFunc, aFirst, aBP, anEpsilonRange, theMaxDist, theMaxPar);
+
+      if(theMaxDist < aValue)
+      {
+        aLast = aBP;
+        aStatus = Standard_True;
+      }
+      else 
+      {
+        theMaxDist = aValue;
+        theMaxPar = aParam;
+        aStatus = Standard_False;
+      }
+
+      if(!aStatus)
+      {
+        aBP = theMaxPar + aMinDelta;
+        MinComputing(aFunc, aBP, aLast, 1.0e-3, theMaxDist, theMaxPar);
+
+        if(theMaxDist < aValue)
+        {
+          aFirst = aBP;
+          aStatus = Standard_True;
+        }
+        else
+        {
+          theMaxDist = aValue;
+          theMaxPar = aParam;
+          aStatus = Standard_False;
+        }
+      }
+    }
+
+    theMaxDist = sqrt(Abs(theMaxDist));
+  }
+  catch (...) {
+    return Standard_False;
+  }
+  //
+  return Standard_True;
+}
+
+//=======================================================================
+// Function : ComputeTolerance
+// purpose : 
+//=======================================================================
+Standard_Boolean BOPTools_AlgoTools::ComputeTolerance
+  (const TopoDS_Face& theFace,
+   const TopoDS_Edge& theEdge,
+   Standard_Real& theMaxDist,
+   Standard_Real& theParameter)
+{
+  Standard_Boolean bRet;
+  Standard_Real aT, aD, aFirst, aLast;
+  TopLoc_Location aLocC, aLocS;
+  //
+  theMaxDist = 0.;
+  theParameter = 0.;
+  bRet = Standard_False;
+  //
+  const Handle(BRep_TEdge)& aTE = *((Handle(BRep_TEdge)*)&theEdge.TShape());
+  //The edge is considered to be same range and not degenerated
+  if ((!aTE->SameRange() && aTE->SameParameter()) ||
+      aTE->Degenerated()) {
+    return bRet;
+  }
+  //
+  Handle(Geom_Curve) aC = Handle(Geom_Curve)::
+    DownCast(BRep_Tool::Curve(theEdge, aLocC, aFirst, aLast)->Copy());
+  aC = new Geom_TrimmedCurve(aC, aFirst, aLast);
+  aC->Transform(aLocC.Transformation());
+  //
+  const Handle(Geom_Surface)& aSurfF = BRep_Tool::Surface(theFace, aLocS);
+  const Handle(Geom_Surface)& aSurf = Handle(Geom_Surface)::
+    DownCast(aSurfF->Copy()->Transformed(aLocS.Transformation()));
+  //
+  Standard_Boolean isPCurveFound = Standard_False;
+  BRep_ListIteratorOfListOfCurveRepresentation itcr(aTE->Curves());
+  for (; itcr.More(); itcr.Next()) {
+    const Handle(BRep_CurveRepresentation)& cr = itcr.Value();
+    if (!(cr->IsCurveOnSurface(aSurfF, aLocS.Predivided(theEdge.Location())))) {
+      continue;
+    }
+    isPCurveFound = Standard_True;
+    //
+    Handle(Geom2d_Curve) aC2d = Handle(Geom2d_Curve)::
+      DownCast(cr->PCurve()->Copy());
+    aC2d = new Geom2d_TrimmedCurve(aC2d, aFirst, aLast);
+      //
+    if(BOPTools_AlgoTools::ComputeTolerance
+       (aC, aC2d, aSurf, aD, aT)) {
+      bRet = Standard_True;
+      if (aD > theMaxDist) {
+        theMaxDist = aD;
+        theParameter = aT;
+      }
+    }
+    //
+    if (cr->IsCurveOnClosedSurface()) {
+      Handle(Geom2d_Curve) aC2d = Handle(Geom2d_Curve)::
+        DownCast(cr->PCurve2()->Copy());
+      aC2d = new Geom2d_TrimmedCurve(aC2d, aFirst, aLast);
+      //
+      if(BOPTools_AlgoTools::ComputeTolerance
+         (aC, aC2d, aSurf, aD, aT)) {
+        bRet = Standard_True;
+        if (aD > theMaxDist) {
+          theMaxDist = aD;
+          theParameter = aT;
+        }
+      }
+    }
+  }
+  //
+  if (isPCurveFound) {
+    return bRet;
+  }
+  //
+  Handle(Geom_Plane) aPlane;
+  Handle(Standard_Type) dtyp = aSurf->DynamicType();
+  //
+  if (dtyp == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
+    aPlane = Handle(Geom_Plane)::
+      DownCast(Handle(Geom_RectangularTrimmedSurface)::
+               DownCast(aSurf)->BasisSurface()->Copy());
+  }
+  else {
+    aPlane = Handle(Geom_Plane)::DownCast(aSurf->Copy());
+  }
+  //
+  if (aPlane.IsNull()) { // not a plane
+    return bRet;
+  }
+  //
+  aPlane = Handle(Geom_Plane)::DownCast(aPlane);//
+  //
+  Handle(GeomAdaptor_HSurface) GAHS = new GeomAdaptor_HSurface(aPlane);
+  Handle(Geom_Curve) ProjOnPlane = 
+    GeomProjLib::ProjectOnPlane (new Geom_TrimmedCurve(aC, aFirst, aLast), 
+                                 aPlane, aPlane->Position().Direction(), 
+                                 Standard_True);
+  Handle(GeomAdaptor_HCurve) aHCurve = new GeomAdaptor_HCurve(ProjOnPlane);
+  //
+  ProjLib_ProjectedCurve proj(GAHS,aHCurve);
+  Handle(Geom2d_Curve) aC2d = Geom2dAdaptor::MakeCurve(proj);
+  aC2d = new Geom2d_TrimmedCurve(aC2d, aFirst, aLast);
+  //
+  if(BOPTools_AlgoTools::ComputeTolerance
+     (aC, aC2d, aPlane, aD, aT)) {
+    bRet = Standard_True;
+    if (aD > theMaxDist) {
+      theMaxDist = aD;
+      theParameter = aT;
+    }
+  }
+  //
+  return bRet;
+}
diff --git a/tests/bugs/modalg_5/bug25410 b/tests/bugs/modalg_5/bug25410
new file mode 100755 (executable)
index 0000000..61e53cc
--- /dev/null
@@ -0,0 +1,23 @@
+puts "============"
+puts "OCC25410"
+puts "============"
+puts ""
+######################################################
+# Tool for extended check of validity of the curve on the surface
+######################################################
+
+pload XSDRAW
+
+testreadiges [locate_data_file bug25410_Tank8.igs] b1
+
+checkcurveonsurf b1
+xdistef e_0 f_0
+bopargcheck b1 /ic #f
+bopargcheck b1 /ics #f
+
+
+testreadiges [locate_data_file bug25410_Tank7.igs] b2
+checkcurveonsurf b2
+xdistef e_0 f_0
+bopargcheck b2 /ic #f
+bopargcheck b2 /ics #f