From f48cb55d3359f4b33a851686169f853dbfa3affd Mon Sep 17 00:00:00 2001
From: jgv <jgv@opencascade.com>
Date: Fri, 17 Feb 2017 18:23:18 +0300
Subject: [PATCH] 0027998: Self-intersection is not detected

    New method CheckFaceSelfIntersection has been added to BOPAlgo_CheckerSI: now self-intersection of each face is found as well as pairs of intersecting faces;

-method IntPatch_Intersection::Perform(S1,D1,TolArc,TolTang) is modified for more effective search of self-interasections in case of Surface Of Extrusion;

-method IntCurve_IntPolyPolyGen::Perform(C1,D1,TolConf,Tol,NbIter) is modified to detect segments of intersections.

Small correction.

Test cases are corrected.

Correction of compiler error

Fix of regressions

Names of shapes correction
---
 src/BOPAlgo/BOPAlgo_ArgumentAnalyzer.cxx    |   6 +-
 src/BOPAlgo/BOPAlgo_CheckerSI.cxx           | 200 ++++++++++++++++++--
 src/BOPAlgo/BOPAlgo_CheckerSI.hxx           |   2 +
 src/BOPTools/BOPTools_AlgoTools2D.cxx       |  47 +----
 src/BOPTools/BOPTools_AlgoTools2D.hxx       |   5 -
 src/Geom2dAPI/Geom2dAPI_InterCurveCurve.cxx |  24 ++-
 src/IntCurve/IntCurve_IntPolyPolyGen.gxx    | 175 +++++++++++++++++
 src/IntPatch/IntPatch_Intersection.cxx      |  44 ++++-
 src/IntTools/IntTools_FaceFace.cxx          |   7 +-
 src/ProjLib/ProjLib.cxx                     |  47 +++++
 src/ProjLib/ProjLib.hxx                     |   4 +
 src/ProjLib/ProjLib_ProjectOnPlane.cxx      |  10 +
 src/ProjLib/ProjLib_ProjectOnPlane.hxx      |   2 +
 tests/bugs/modalg_6/bug27341_312            |   2 +-
 tests/bugs/modalg_6/bug27998_1              |  17 ++
 tests/bugs/modalg_6/bug27998_2              |  17 ++
 tests/bugs/modalg_6/bug27998_3              |  23 +++
 17 files changed, 551 insertions(+), 81 deletions(-)
 create mode 100644 tests/bugs/modalg_6/bug27998_1
 create mode 100644 tests/bugs/modalg_6/bug27998_2
 create mode 100644 tests/bugs/modalg_6/bug27998_3

diff --git a/src/BOPAlgo/BOPAlgo_ArgumentAnalyzer.cxx b/src/BOPAlgo/BOPAlgo_ArgumentAnalyzer.cxx
index 6138f91bda..ed181df9b2 100644
--- a/src/BOPAlgo/BOPAlgo_ArgumentAnalyzer.cxx
+++ b/src/BOPAlgo/BOPAlgo_ArgumentAnalyzer.cxx
@@ -384,12 +384,14 @@ void BOPAlgo_ArgumentAnalyzer::TestSelfInterferences()
       if(ii == 0) {
         aResult.SetShape1(myShape1);
         aResult.AddFaultyShape1(aS1);
-        aResult.AddFaultyShape1(aS2);
+        if (!aS1.IsSame(aS2))
+          aResult.AddFaultyShape1(aS2);
       }
       else {
         aResult.SetShape2(myShape2);
         aResult.AddFaultyShape2(aS1);
-        aResult.AddFaultyShape2(aS2);
+        if (!aS1.IsSame(aS2))
+          aResult.AddFaultyShape2(aS2);
       }
       aResult.SetCheckStatus(BOPAlgo_SelfIntersect);
       myResult.Append(aResult);
diff --git a/src/BOPAlgo/BOPAlgo_CheckerSI.cxx b/src/BOPAlgo/BOPAlgo_CheckerSI.cxx
index 323b5af6f0..06d6360a04 100644
--- a/src/BOPAlgo/BOPAlgo_CheckerSI.cxx
+++ b/src/BOPAlgo/BOPAlgo_CheckerSI.cxx
@@ -19,6 +19,7 @@
 
 #include <BOPAlgo_CheckerSI.hxx>
 #include <BOPCol_MapOfShape.hxx>
+#include <BOPCol_Parallel.hxx>
 #include <BOPDS_DS.hxx>
 #include <BOPDS_Interf.hxx>
 #include <BOPDS_IteratorSI.hxx>
@@ -34,9 +35,83 @@
 #include <BOPTools_AlgoTools.hxx>
 #include <BRepBuilderAPI_Copy.hxx>
 #include <IntTools_Context.hxx>
+#include <IntTools_Tools.hxx>
+#include <IntTools_FaceFace.hxx>
 #include <Standard_ErrorHandler.hxx>
 #include <Standard_Failure.hxx>
 #include <TopTools_ListOfShape.hxx>
+#include <BRep_Tool.hxx>
+#include <gp_Torus.hxx>
+
+//=======================================================================
+//class    : BOPAlgo_FaceSelfIntersect
+//purpose  : 
+//=======================================================================
+class BOPAlgo_FaceSelfIntersect : 
+  public IntTools_FaceFace,
+  public BOPAlgo_Algo {
+
+ public:
+  DEFINE_STANDARD_ALLOC
+
+  BOPAlgo_FaceSelfIntersect() : 
+    IntTools_FaceFace(),  
+    BOPAlgo_Algo(),
+    myIF(-1), myTolF(1.e-7) {
+  }
+  //
+  virtual ~BOPAlgo_FaceSelfIntersect() {
+  }
+  //
+  void SetIndex(const Standard_Integer nF) {
+    myIF = nF;
+  }
+  //
+  Standard_Integer IndexOfFace() const {
+    return myIF;
+  }
+  //
+  void SetFace(const TopoDS_Face& aF) {
+    myF = aF;
+  }
+  //
+  const TopoDS_Face& Face()const {
+    return myF;
+  }
+  //
+  void SetTolF(const Standard_Real aTolF) {
+    myTolF = aTolF;
+  }
+  //
+  Standard_Real TolF() const{
+    return myTolF;
+  }
+  //
+  virtual void Perform() {
+    BOPAlgo_Algo::UserBreak();
+    IntTools_FaceFace::Perform(myF, myF);
+  }
+  //
+ protected:
+  Standard_Integer myIF;
+  Standard_Real myTolF;
+  TopoDS_Face myF;
+};
+//end of definition of class BOPAlgo_FaceSelfIntersect
+
+//=======================================================================
+
+typedef BOPCol_NCVector
+  <BOPAlgo_FaceSelfIntersect> BOPAlgo_VectorOfFaceSelfIntersect; 
+//
+typedef BOPCol_Functor 
+  <BOPAlgo_FaceSelfIntersect,
+  BOPAlgo_VectorOfFaceSelfIntersect> BOPAlgo_FaceSelfIntersectFunctor;
+//
+typedef BOPCol_Cnt 
+  <BOPAlgo_FaceSelfIntersectFunctor,
+  BOPAlgo_VectorOfFaceSelfIntersect> BOPAlgo_FaceSelfIntersectCnt;
+
 
 //=======================================================================
 //function : 
@@ -116,6 +191,8 @@ void BOPAlgo_CheckerSI::Perform()
     // Perform intersection of sub shapes
     BOPAlgo_PaveFiller::Perform();
     //
+    CheckFaceSelfIntersection();
+    
     // Perform intersection with solids
     if (!myErrorStatus)
       PerformVZ();
@@ -150,8 +227,7 @@ void BOPAlgo_CheckerSI::PostTreat()
   //
   BOPDS_MapOfPair& aMPK=
     *((BOPDS_MapOfPair*)&myDS->Interferences());
-  aMPK.Clear();
-  //
+
   // 0
   BOPDS_VectorOfInterfVV& aVVs=myDS->InterfVV();
   aNb=aVVs.Extent();
@@ -238,23 +314,27 @@ void BOPAlgo_CheckerSI::PostTreat()
       continue;
     }
     //
-    iFound=0;
-    if (bTangentFaces) {
-      const TopoDS_Face& aF1=*((TopoDS_Face*)&myDS->Shape(n1));
-      const TopoDS_Face& aF2=*((TopoDS_Face*)&myDS->Shape(n2));
-      bFlag=BOPTools_AlgoTools::AreFacesSameDomain
-        (aF1, aF2, myContext, myFuzzyValue);
-      if (bFlag) {
-        ++iFound;
-      }
-    }
-    else {
-      for (j=0; j!=aNbC; ++j) {
-        const BOPDS_Curve& aNC=aVC(j);
-        const BOPDS_ListOfPaveBlock& aLPBC=aNC.PaveBlocks();
-        if (aLPBC.Extent()) {
+    iFound = (n1 == n2) ? 1 : 0;
+    //case of self-intersection inside one face
+    if (!iFound)
+    {
+      if (bTangentFaces) {
+        const TopoDS_Face& aF1=*((TopoDS_Face*)&myDS->Shape(n1));
+        const TopoDS_Face& aF2=*((TopoDS_Face*)&myDS->Shape(n2));
+        bFlag=BOPTools_AlgoTools::AreFacesSameDomain
+          (aF1, aF2, myContext, myFuzzyValue);
+        if (bFlag) {
           ++iFound;
-          break;
+        }
+      }
+      else {
+        for (j=0; j!=aNbC; ++j) {
+          const BOPDS_Curve& aNC=aVC(j);
+          const BOPDS_ListOfPaveBlock& aLPBC=aNC.PaveBlocks();
+          if (aLPBC.Extent()) {
+            ++iFound;
+            break;
+          }
         }
       }
     }
@@ -315,3 +395,87 @@ void BOPAlgo_CheckerSI::PostTreat()
     aMPK.Add(aPK);
   }
 }
+
+//=======================================================================
+//function : CheckFaceSelfIntersection
+//purpose  : 
+//=======================================================================
+void BOPAlgo_CheckerSI::CheckFaceSelfIntersection()
+{
+  if (myLevelOfCheck < 5)
+    return;
+  
+  BOPDS_Pair aPK;
+
+  BOPDS_MapOfPair& aMPK=
+    *((BOPDS_MapOfPair*)&myDS->Interferences());
+  aMPK.Clear();
+  
+  BOPAlgo_VectorOfFaceSelfIntersect aVFace;
+  
+  Standard_Integer aNbS=myDS->NbSourceShapes();
+  
+  //
+  for (Standard_Integer i = 0; i < aNbS; i++)
+  {
+    const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
+    if (aSI.ShapeType() != TopAbs_FACE)
+      continue;
+    //
+    const TopoDS_Face& aF = (*(TopoDS_Face*)(&aSI.Shape()));
+    BRepAdaptor_Surface BAsurf(aF, Standard_False);
+    GeomAbs_SurfaceType aSurfType = BAsurf.GetType();
+    if (aSurfType == GeomAbs_Plane ||
+        aSurfType == GeomAbs_Cylinder ||
+        aSurfType == GeomAbs_Cone ||
+        aSurfType == GeomAbs_Sphere)
+      continue;
+
+    if (aSurfType == GeomAbs_Torus)
+    {
+      gp_Torus aTorus = BAsurf.Torus();
+      Standard_Real aMajorRadius = aTorus.MajorRadius();
+      Standard_Real aMinorRadius = aTorus.MinorRadius();
+      if (aMajorRadius > aMinorRadius + Precision::Confusion())
+        continue;
+    }
+
+    Standard_Real aTolF = BRep_Tool::Tolerance(aF);
+    
+    BOPAlgo_FaceSelfIntersect& aFaceSelfIntersect = aVFace.Append1();
+    //
+    aFaceSelfIntersect.SetIndex(i);
+    aFaceSelfIntersect.SetFace(aF);
+    aFaceSelfIntersect.SetTolF(aTolF);
+    //
+    aFaceSelfIntersect.SetProgressIndicator(myProgressIndicator);
+  }
+  
+  Standard_Integer aNbFace = aVFace.Extent();
+  //======================================================
+  BOPAlgo_FaceSelfIntersectCnt::Perform(myRunParallel, aVFace);
+  //======================================================
+  //
+  for (Standard_Integer k = 0; k < aNbFace; k++)
+  {
+    BOPAlgo_FaceSelfIntersect& aFaceSelfIntersect = aVFace(k);
+    //
+    Standard_Integer nF = aFaceSelfIntersect.IndexOfFace();
+
+    Standard_Boolean bIsDone = aFaceSelfIntersect.IsDone();
+    if (bIsDone)
+    {
+      const IntTools_SequenceOfCurves& aCvsX = aFaceSelfIntersect.Lines();
+      const IntTools_SequenceOfPntOn2Faces& aPntsX = aFaceSelfIntersect.Points();
+      //
+      Standard_Integer aNbCurves = aCvsX.Length();
+      Standard_Integer aNbPoints = aPntsX.Length();
+      //
+      if (aNbCurves || aNbPoints)
+      {
+        aPK.SetIndices(nF, nF);
+        aMPK.Add(aPK);
+      }
+    }
+  }
+}
diff --git a/src/BOPAlgo/BOPAlgo_CheckerSI.hxx b/src/BOPAlgo/BOPAlgo_CheckerSI.hxx
index 69cdf70786..f764f591e5 100644
--- a/src/BOPAlgo/BOPAlgo_CheckerSI.hxx
+++ b/src/BOPAlgo/BOPAlgo_CheckerSI.hxx
@@ -68,6 +68,8 @@ protected:
   //! Treats the intersection results
   Standard_EXPORT void PostTreat();
 
+  Standard_EXPORT void CheckFaceSelfIntersection();
+
   //! Methods for intersection with solids
 
   //! Vertex/Solid intersection
diff --git a/src/BOPTools/BOPTools_AlgoTools2D.cxx b/src/BOPTools/BOPTools_AlgoTools2D.cxx
index 657c397f70..9697b92f56 100644
--- a/src/BOPTools/BOPTools_AlgoTools2D.cxx
+++ b/src/BOPTools/BOPTools_AlgoTools2D.cxx
@@ -57,6 +57,7 @@
 #include <IntTools_Tools.hxx>
 #include <Precision.hxx>
 #include <ProjLib_ProjectedCurve.hxx>
+#include <ProjLib.hxx>
 #include <Standard_ConstructionError.hxx>
 #include <Standard_NotImplemented.hxx>
 #include <TopExp.hxx>
@@ -638,24 +639,24 @@ void BOPTools_AlgoTools2D::MakePCurveOnFace
     }
     //
     ProjLib_ProjectedCurve aProj1(aBAHS, aBAHC, aTR);
-    BOPTools_AlgoTools2D::MakePCurveOfType(aProj1, aC2D);
+    ProjLib::MakePCurveOfType(aProj1, aC2D);
     aTolR = aProj1.GetTolerance();
   } 
   else {
     ProjLib_ProjectedCurve aProjCurv(aBAHS, aBAHC);// 1
-    BOPTools_AlgoTools2D::MakePCurveOfType(aProjCurv, aC2D);
+    ProjLib::MakePCurveOfType(aProjCurv, aC2D);
     aTolR=aProjCurv.GetTolerance();
   }
   //
   if (aC2D.IsNull()) { 
     ProjLib_ProjectedCurve aProjCurvAgain(aBAHS, aBAHC, TolReached2d);// 2
-    BOPTools_AlgoTools2D::MakePCurveOfType(aProjCurvAgain, aC2D);
+    ProjLib::MakePCurveOfType(aProjCurvAgain, aC2D);
     aTolR = aProjCurvAgain.GetTolerance();
     //
     if (aC2D.IsNull()) { 
       Standard_Real aTR=0.0001;
       ProjLib_ProjectedCurve aProj3(aBAHS, aBAHC, aTR);// 3
-      BOPTools_AlgoTools2D::MakePCurveOfType(aProj3, aC2D);
+      ProjLib::MakePCurveOfType(aProj3, aC2D);
       aTolR = aProj3.GetTolerance();
     }
   }
@@ -685,42 +686,6 @@ void BOPTools_AlgoTools2D::MakePCurveOnFace
   }
 }
 
-//=======================================================================
-//function : MakePCurveOfType
-//purpose  : 
-//=======================================================================
-void  BOPTools_AlgoTools2D::MakePCurveOfType
-  (const ProjLib_ProjectedCurve& PC, 
-   Handle(Geom2d_Curve)& C2D)
-{
-  
-  switch (PC.GetType()) {
-
-  case GeomAbs_Line : 
-    C2D = new Geom2d_Line(PC.Line()); 
-    break;
-  case GeomAbs_Circle : 
-    C2D = new Geom2d_Circle(PC.Circle());
-    break;
-  case GeomAbs_Ellipse :
-    C2D = new Geom2d_Ellipse(PC.Ellipse());
-    break;
-  case GeomAbs_Parabola : 
-    C2D = new Geom2d_Parabola(PC.Parabola()); 
-    break;
-  case GeomAbs_Hyperbola : 
-    C2D = new Geom2d_Hyperbola(PC.Hyperbola()); 
-    break;
-  case GeomAbs_BSplineCurve :
-    C2D = PC.BSpline(); 
-    break;
-  case GeomAbs_BezierCurve : 
-  case GeomAbs_OtherCurve : 
-    default :
-    throw Standard_NotImplemented("BOPTools_AlgoTools2D::MakePCurveOfType");
-    break;
-  }
-}
 //=======================================================================
 //function : CheckEdgeLength
 //purpose  : 
@@ -932,4 +897,4 @@ void BOPTools_AlgoTools2D::IsEdgeIsoline( const TopoDS_Edge& theE,
 
   isTheUIso = (aDPv <= aTol);
   isTheVIso = (aDPu <= aTol);
-}
\ No newline at end of file
+}
diff --git a/src/BOPTools/BOPTools_AlgoTools2D.hxx b/src/BOPTools/BOPTools_AlgoTools2D.hxx
index 6407253570..f6f68b5edc 100644
--- a/src/BOPTools/BOPTools_AlgoTools2D.hxx
+++ b/src/BOPTools/BOPTools_AlgoTools2D.hxx
@@ -191,11 +191,6 @@ public:
                                                 Standard_Real& aToler,
                                                 const Handle(IntTools_Context)& theContext = Handle(IntTools_Context)());
   
-
-  //! Make empty  P-Curve <aC> of relevant to <PC> type
-  Standard_EXPORT static void MakePCurveOfType (const ProjLib_ProjectedCurve& PC, Handle(Geom2d_Curve)& aC);
-  
-
   //! Attach P-Curve from the edge <aEold> on surface <aF>
   //! to the edge <aEnew>
   //! Returns 0 in case of success
diff --git a/src/Geom2dAPI/Geom2dAPI_InterCurveCurve.cxx b/src/Geom2dAPI/Geom2dAPI_InterCurveCurve.cxx
index e3555996ae..537a1ebb0a 100644
--- a/src/Geom2dAPI/Geom2dAPI_InterCurveCurve.cxx
+++ b/src/Geom2dAPI/Geom2dAPI_InterCurveCurve.cxx
@@ -180,13 +180,22 @@ void Geom2dAPI_InterCurveCurve::Segment
   Standard_OutOfRange_Raise_if(theIndex < 1 || theIndex > NbSegments(),
                                "Geom2dAPI_InterCurveCurve::Segment");
 
-  Standard_NullObject_Raise_if(myCurve1.IsNull() || myCurve2.IsNull(),
+  Standard_NullObject_Raise_if(myCurve1.IsNull(),
                                "Geom2dAPI_InterCurveCurve::Segment");
 
-  Standard_Real aU1 = myCurve1->FirstParameter(),
-                aU2 = myCurve1->LastParameter(),
-                aV1 = myCurve2->FirstParameter(),
-                aV2 = myCurve2->LastParameter();
+  Standard_Real aU1, aU2, aV1, aV2;
+  aU1 = myCurve1->FirstParameter();
+  aU2 = myCurve1->LastParameter();
+  if (myCurve2.IsNull())
+  {
+    aV1 = aU1;
+    aV2 = aU2;
+  }
+  else
+  {
+    aV1 = myCurve2->FirstParameter();
+    aV2 = myCurve2->LastParameter();
+  }
 
   const IntRes2d_IntersectionSegment& aSeg = myIntersector.Segment(theIndex);
   const Standard_Boolean isOpposite = aSeg.IsOpposite();
@@ -214,5 +223,8 @@ void Geom2dAPI_InterCurveCurve::Segment
   }
 
   theCurve1 = new Geom2d_TrimmedCurve(myCurve1, aU1, aU2);
-  theCurve2 = new Geom2d_TrimmedCurve(myCurve2, aV1, aV2);
+  if (myCurve2.IsNull())
+    theCurve2 = new Geom2d_TrimmedCurve(myCurve1, aV1, aV2);
+  else
+    theCurve2 = new Geom2d_TrimmedCurve(myCurve2, aV1, aV2);
 }
diff --git a/src/IntCurve/IntCurve_IntPolyPolyGen.gxx b/src/IntCurve/IntCurve_IntPolyPolyGen.gxx
index aa868050c4..ae3c4bfb99 100644
--- a/src/IntCurve/IntCurve_IntPolyPolyGen.gxx
+++ b/src/IntCurve/IntCurve_IntPolyPolyGen.gxx
@@ -486,6 +486,181 @@ void IntCurve_IntPolyPolyGen::Perform( const TheCurve& C1
     delete [] PtrSegIndex1;
     delete [] PtrSegIndex2;
   }
+
+  //----------------------------------------------------------------------
+  //-- Processing of TangentZone
+  //----------------------------------------------------------------------
+  Standard_Integer Nbtz = InterPP.NbTangentZones();
+  for(Standard_Integer tz=1; tz <= Nbtz; tz++) {
+    Standard_Integer NbPnts = InterPP.ZoneValue(tz).NumberOfPoints();
+    //====================================================================
+    //== Find the first and the last point in the tangency zone.
+    //====================================================================
+    Standard_Real ParamSupOnCurve2,ParamInfOnCurve2;
+    Standard_Real ParamSupOnCurve1,ParamInfOnCurve1;
+//    Standard_Integer SegIndex,SegIndex1onP1,SegIndex1onP2,SegIndex2onP1,SegIndex2onP2;
+    Standard_Integer SegIndex1onP1,SegIndex1onP2;
+    Intf_PIType Type;
+    Standard_Real ParamOnLine;
+    Standard_Real PolyUInf,PolyUSup,PolyVInf,PolyVSup;
+    ParamSupOnCurve2=ParamSupOnCurve1=PolyUSup=PolyVSup=-RealLast();
+    ParamInfOnCurve2=ParamInfOnCurve1=PolyUInf=PolyVInf= RealLast();
+    for(Standard_Integer qq=1;qq<=NbPnts;qq++) { 
+      const Intf_SectionPoint& SPnt1 = InterPP.ZoneValue(tz).GetPoint(qq);
+      //====================================================================
+      //== The zones of tangency are discretized 
+      //== Test of stop : Check if 
+      //==     (Deflection  < Tolerance)
+      //==  Or (Sample < EpsX)   (normally the first condition is 
+      //==                           more strict)
+      //====================================================================
+//      Standard_Real _PolyUInf,_PolyUSup,_PolyVInf,_PolyVSup;
+      Standard_Real _PolyUInf,_PolyVInf;
+
+      SPnt1.InfoFirst(Type,SegIndex1onP1,ParamOnLine);
+      if(SegIndex1onP1 > Poly1.NbSegments()) { SegIndex1onP1--; ParamOnLine = 1.0; }
+      if(SegIndex1onP1 <= 0) { SegIndex1onP1=1; ParamOnLine = 0.0; }
+      _PolyUInf = Poly1.ApproxParamOnCurve(SegIndex1onP1,ParamOnLine);
+      
+      SPnt1.InfoSecond(Type,SegIndex1onP2,ParamOnLine);
+      if(SegIndex1onP2 > Poly1.NbSegments()) { SegIndex1onP2--; ParamOnLine = 1.0; }
+      if(SegIndex1onP2 <= 0) { SegIndex1onP2=1; ParamOnLine = 0.0; }
+      _PolyVInf = Poly1.ApproxParamOnCurve(SegIndex1onP2,ParamOnLine);
+      
+      //----------------------------------------------------------------------
+
+      if(ParamInfOnCurve1 > _PolyUInf) ParamInfOnCurve1=_PolyUInf;
+      if(ParamInfOnCurve2 > _PolyVInf) ParamInfOnCurve2=_PolyVInf;
+
+      if(ParamSupOnCurve1 < _PolyUInf) ParamSupOnCurve1=_PolyUInf;
+      if(ParamSupOnCurve2 < _PolyVInf) ParamSupOnCurve2=_PolyVInf;
+    }
+
+    PolyUInf= ParamInfOnCurve1;
+    PolyUSup= ParamSupOnCurve1;
+    PolyVInf= ParamInfOnCurve2;
+    PolyVSup= ParamSupOnCurve2;
+    
+    TheCurveTool::D0(C1,PolyUInf,P1);
+    TheCurveTool::D0(C1,PolyVInf,P2);
+    Standard_Real distmemesens = P1.SquareDistance(P2);
+    TheCurveTool::D0(C1,PolyVSup,P2);
+    Standard_Real distdiffsens = P1.SquareDistance(P2);
+    if(distmemesens > distdiffsens) { 
+      Standard_Real qwerty=PolyVInf; PolyVInf=PolyVSup; PolyVSup=qwerty;
+    }
+
+    //-----------------------------------------------------------------
+    //-- Calculate Positions of Points on the curve and  
+    //-- Transitions on each limit of the segment
+    
+    IntRes2d_Position Pos1 = IntRes2d_Middle;
+    IntRes2d_Position Pos2 = IntRes2d_Middle;
+    IntRes2d_Transition  Trans1,Trans2;
+    
+    TheCurveTool::D1(C1,PolyUInf,P1,Tan1);
+    TheCurveTool::D1(C1,PolyVInf,P2,Tan2);
+    
+    if(P1.Distance(DomainOnCurve1.FirstPoint())<=DomainOnCurve1.FirstTolerance())    { 
+      Pos1 = IntRes2d_Head;
+    }
+    else if(P1.Distance(DomainOnCurve1.LastPoint())<=DomainOnCurve1.LastTolerance()) { 
+      Pos1 = IntRes2d_End;  
+    }
+    if(P2.Distance(DomainOnCurve2.FirstPoint())<=DomainOnCurve2.FirstTolerance())    { 
+      Pos2 = IntRes2d_Head; 
+    }
+    else if(P2.Distance(DomainOnCurve2.LastPoint())<=DomainOnCurve2.LastTolerance()) { 
+      Pos2 = IntRes2d_End;  
+    }
+    
+    if(Pos1==IntRes2d_Middle && Pos2!=IntRes2d_Middle) { 
+      PolyUInf=TheProjPCur::FindParameter( C1,P2,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
+    }
+    else if(Pos1!=IntRes2d_Middle && Pos2==IntRes2d_Middle) { 
+      PolyVInf=TheProjPCur::FindParameter( C1,P1,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
+    }
+    else if(Abs(ParamInfOnCurve1-ParamSupOnCurve1) > Abs(ParamInfOnCurve2-ParamSupOnCurve2)) { 
+      PolyVInf=TheProjPCur::FindParameter( C1,P1,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
+    }
+    else { 
+      PolyUInf=TheProjPCur::FindParameter( C1,P2,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
+    }
+    
+
+    
+    if(IntImpParGen::DetermineTransition( Pos1,Tan1,Trans1,Pos2,Tan2,Trans2,TolConf) 
+       == Standard_False)
+    {
+      TheCurveTool::D2(C1,PolyUInf,P1,Tan1,Norm1);
+      TheCurveTool::D2(C1,PolyVInf,P2,Tan2,Norm2);
+      IntImpParGen::DetermineTransition(Pos1,Tan1,Norm1,Trans1,
+                                        Pos2,Tan2,Norm2,Trans2,TolConf);
+    }
+    IntRes2d_IntersectionPoint PtSeg1(P1,PolyUInf,PolyVInf
+					,Trans1,Trans2,Standard_False);
+    //----------------------------------------------------------------------
+    
+    if((Abs(PolyUInf-PolyUSup) <= TheCurveTool::EpsX(C1)) ||
+       (Abs(PolyVInf-PolyVSup) <= TheCurveTool::EpsX(C1)))
+    { 
+      //bad segment
+    }
+    else 
+    { 
+      TheCurveTool::D1(C1,PolyUSup,P1,Tan1);
+      TheCurveTool::D1(C1,PolyVSup,P2,Tan2);
+      Pos1 = IntRes2d_Middle; Pos2 = IntRes2d_Middle;
+      
+      if(P1.Distance(DomainOnCurve1.FirstPoint())<=DomainOnCurve1.FirstTolerance())    { 
+        Pos1 = IntRes2d_Head; 
+      }
+      else if(P1.Distance(DomainOnCurve1.LastPoint())<=DomainOnCurve1.LastTolerance()) { 
+        Pos1 = IntRes2d_End;  
+      }
+      if(P2.Distance(DomainOnCurve2.FirstPoint())<=DomainOnCurve2.FirstTolerance())    { 
+        Pos2 = IntRes2d_Head; 
+      }
+      else if(P2.Distance(DomainOnCurve2.LastPoint())<=DomainOnCurve2.LastTolerance()) { 
+        Pos2 = IntRes2d_End;  
+      }
+      
+      
+      if(Pos1==IntRes2d_Middle && Pos2!=IntRes2d_Middle) { 
+        PolyUSup=TheProjPCur::FindParameter( C1,P2,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
+      }
+      else if(Pos1!=IntRes2d_Middle && Pos2==IntRes2d_Middle) { 
+        PolyVSup=TheProjPCur::FindParameter( C1,P1,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
+      }
+      else if(Abs(ParamInfOnCurve1-ParamSupOnCurve1) > Abs(ParamInfOnCurve2-ParamSupOnCurve2)) { 
+        PolyVSup=TheProjPCur::FindParameter( C1,P1,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
+      }
+      else { 
+        PolyUSup=TheProjPCur::FindParameter( C1,P2,D1.FirstParameter(),D1.LastParameter(),TheCurveTool::EpsX(C1));
+      }
+      
+      if(IntImpParGen::DetermineTransition( Pos1,Tan1,Trans1,Pos2,Tan2,Trans2,TolConf)
+         ==Standard_False) { 
+        TheCurveTool::D2(C1,PolyUSup,P1,Tan1,Norm1);
+        TheCurveTool::D2(C1,PolyVSup,P2,Tan2,Norm2);
+        IntImpParGen::DetermineTransition(Pos1,Tan1,Norm1,Trans1,
+                                          Pos2,Tan2,Norm2,Trans2,TolConf);
+      }
+      IntRes2d_IntersectionPoint PtSeg2(P1,PolyUSup,PolyVSup
+                                        ,Trans1,Trans2,Standard_False);
+      
+      Standard_Boolean Oppos = (Tan1.Dot(Tan2) > 0.0)? Standard_False : Standard_True;
+      if(ParamInfOnCurve1 > ParamSupOnCurve1) {
+        IntRes2d_IntersectionSegment Seg(PtSeg2,PtSeg1,Oppos,Standard_False);
+        Append(Seg);
+      }
+      else { 
+        IntRes2d_IntersectionSegment Seg(PtSeg1,PtSeg2,Oppos,Standard_False);
+        Append(Seg);
+      }
+    }
+  } //end of processing of TangentZone
+  
  done = Standard_True;
 }
 
diff --git a/src/IntPatch/IntPatch_Intersection.cxx b/src/IntPatch/IntPatch_Intersection.cxx
index 0a441abe5b..6213b3541a 100644
--- a/src/IntPatch/IntPatch_Intersection.cxx
+++ b/src/IntPatch/IntPatch_Intersection.cxx
@@ -26,6 +26,15 @@
 #include <IntPatch_WLine.hxx>
 #include <IntPatch_WLineTool.hxx>
 
+#include <ProjLib_ProjectOnPlane.hxx>
+#include <Geom_Plane.hxx>
+#include <GeomAdaptor_HSurface.hxx>
+#include <GeomAdaptor_HCurve.hxx>
+#include <ProjLib_ProjectedCurve.hxx>
+#include <Geom2dInt_GInter.hxx>
+#include <Geom2dAdaptor_Curve.hxx>
+#include <ProjLib.hxx>
+
 //======================================================================
 // function: SequenceOfLine
 //======================================================================
@@ -129,12 +138,35 @@ void IntPatch_Intersection::Perform(const Handle(Adaptor3d_HSurface)&  S1,
 
   switch (S1->GetType())
   { 
-    case GeomAbs_Plane:
-    case GeomAbs_Cylinder:
-    case GeomAbs_Sphere:
-    case GeomAbs_Cone:
-    case GeomAbs_Torus: break;
-    default:
+  case GeomAbs_Plane:
+  case GeomAbs_Cylinder:
+  case GeomAbs_Sphere:
+  case GeomAbs_Cone:
+  case GeomAbs_Torus:
+    break;
+  case GeomAbs_SurfaceOfExtrusion:
+    {
+      gp_Dir aDirection = S1->Direction();
+      gp_Ax3 anAxis(gp::Origin(), aDirection);
+      Handle(Adaptor3d_HCurve) aBasisCurve = S1->BasisCurve();
+      ProjLib_ProjectOnPlane Projector(anAxis);
+      Projector.Load(aBasisCurve, Precision::Confusion());
+      Handle(GeomAdaptor_HCurve) aProjCurve = Projector.GetResult();
+      Handle(Geom_Plane) aPlane = new Geom_Plane(anAxis);
+      Handle(GeomAdaptor_HSurface) aGAHsurf = new GeomAdaptor_HSurface(aPlane);
+      ProjLib_ProjectedCurve aProjectedCurve(aGAHsurf, aProjCurve);
+      Handle(Geom2d_Curve) aPCurve;
+      ProjLib::MakePCurveOfType(aProjectedCurve, aPCurve);
+      Geom2dAdaptor_Curve AC(aPCurve,
+                             aProjectedCurve.FirstParameter(),
+                             aProjectedCurve.LastParameter());
+      Geom2dInt_GInter Intersector(AC,
+                                   Precision::Confusion(),
+                                   Precision::Confusion());
+      if (Intersector.IsDone() && Intersector.IsEmpty())
+        break;
+    }
+  default:
     {
       IntPatch_PrmPrmIntersection interpp;
       interpp.Perform(S1,D1,TolTang,TolArc,myFleche,myUVMaxStep);
diff --git a/src/IntTools/IntTools_FaceFace.cxx b/src/IntTools/IntTools_FaceFace.cxx
index ccd519642e..e802a09299 100644
--- a/src/IntTools/IntTools_FaceFace.cxx
+++ b/src/IntTools/IntTools_FaceFace.cxx
@@ -627,8 +627,11 @@ void IntTools_FaceFace::Perform(const TopoDS_Face& aF1,
 #endif
 
   const Standard_Boolean isGeomInt = isTreatAnalityc(aBAS1, aBAS2, myTol);
-  myIntersector.Perform(myHS1, dom1, myHS2, dom2, TolArc, TolTang, 
-                                  myListOfPnts, RestrictLine, isGeomInt);
+  if (aF1.IsSame(aF2))
+    myIntersector.Perform(myHS1, dom1, TolArc, TolTang);
+  else
+    myIntersector.Perform(myHS1, dom1, myHS2, dom2, TolArc, TolTang, 
+                          myListOfPnts, RestrictLine, isGeomInt);
 
   myIsDone = myIntersector.IsDone();
 
diff --git a/src/ProjLib/ProjLib.cxx b/src/ProjLib/ProjLib.cxx
index e536aacd8b..c9f380bcc8 100644
--- a/src/ProjLib/ProjLib.cxx
+++ b/src/ProjLib/ProjLib.cxx
@@ -39,6 +39,15 @@
 #include <ProjLib_Plane.hxx>
 #include <ProjLib_Sphere.hxx>
 #include <ProjLib_Torus.hxx>
+#include <ProjLib_ProjectedCurve.hxx>
+#include <Geom2d_Line.hxx>
+#include <Geom2d_Circle.hxx>
+#include <Geom2d_Ellipse.hxx>
+#include <Geom2d_Parabola.hxx>
+#include <Geom2d_Hyperbola.hxx>
+#include <Geom2d_BSplineCurve.hxx>
+#include <Geom2d_BezierCurve.hxx>
+#include <Standard_NotImplemented.hxx>
 
 //=======================================================================
 //function : Project
@@ -234,3 +243,41 @@ gp_Lin2d  ProjLib::Project(const gp_Torus& To, const gp_Circ& Ci)
   ProjLib_Torus Proj( To, Ci);
   return Proj.Line();
 }
+
+//=======================================================================
+//function : MakePCurveOfType
+//purpose  : 
+//=======================================================================
+void  ProjLib::MakePCurveOfType
+  (const ProjLib_ProjectedCurve& PC, 
+   Handle(Geom2d_Curve)& C2D)
+{
+  
+  switch (PC.GetType()) {
+
+  case GeomAbs_Line : 
+    C2D = new Geom2d_Line(PC.Line()); 
+    break;
+  case GeomAbs_Circle : 
+    C2D = new Geom2d_Circle(PC.Circle());
+    break;
+  case GeomAbs_Ellipse :
+    C2D = new Geom2d_Ellipse(PC.Ellipse());
+    break;
+  case GeomAbs_Parabola : 
+    C2D = new Geom2d_Parabola(PC.Parabola()); 
+    break;
+  case GeomAbs_Hyperbola : 
+    C2D = new Geom2d_Hyperbola(PC.Hyperbola()); 
+    break;
+  case GeomAbs_BSplineCurve :
+    C2D = PC.BSpline(); 
+    break;
+  case GeomAbs_BezierCurve : 
+  case GeomAbs_OtherCurve : 
+    default :
+    Standard_NotImplemented::Raise
+      ("ProjLib::MakePCurveOfType");
+    break;
+  }
+}
diff --git a/src/ProjLib/ProjLib.hxx b/src/ProjLib/ProjLib.hxx
index a06c3dfde4..b5fa7ac097 100644
--- a/src/ProjLib/ProjLib.hxx
+++ b/src/ProjLib/ProjLib.hxx
@@ -20,6 +20,7 @@
 #include <Standard.hxx>
 #include <Standard_DefineAlloc.hxx>
 #include <Standard_Handle.hxx>
+#include <Geom2d_Curve.hxx>
 
 class gp_Pnt2d;
 class gp_Pln;
@@ -128,6 +129,9 @@ public:
   
   Standard_EXPORT static gp_Lin2d Project (const gp_Torus& To, const gp_Circ& Ci);
 
+  //! Make empty  P-Curve <aC> of relevant to <PC> type
+  Standard_EXPORT static void MakePCurveOfType (const ProjLib_ProjectedCurve& PC,
+                                                Handle(Geom2d_Curve)& aC);
 
 
 
diff --git a/src/ProjLib/ProjLib_ProjectOnPlane.cxx b/src/ProjLib/ProjLib_ProjectOnPlane.cxx
index b8b9a036f4..c31d8f6a5a 100644
--- a/src/ProjLib/ProjLib_ProjectOnPlane.cxx
+++ b/src/ProjLib/ProjLib_ProjectOnPlane.cxx
@@ -898,6 +898,16 @@ const Handle(Adaptor3d_HCurve)& ProjLib_ProjectOnPlane::GetCurve() const
   return myCurve;
 }
 
+//=======================================================================
+//function : GetResult
+//purpose  : 
+//=======================================================================
+
+const Handle(GeomAdaptor_HCurve)& ProjLib_ProjectOnPlane::GetResult() const
+{
+  return myResult;
+}
+
 
 //=======================================================================
 //function : FirstParameter
diff --git a/src/ProjLib/ProjLib_ProjectOnPlane.hxx b/src/ProjLib/ProjLib_ProjectOnPlane.hxx
index 9b0a6d0dc5..e3d50ce496 100644
--- a/src/ProjLib/ProjLib_ProjectOnPlane.hxx
+++ b/src/ProjLib/ProjLib_ProjectOnPlane.hxx
@@ -92,6 +92,8 @@ public:
   
   Standard_EXPORT const Handle(Adaptor3d_HCurve)& GetCurve() const;
   
+  Standard_EXPORT const Handle(GeomAdaptor_HCurve)& GetResult() const;
+  
   Standard_EXPORT Standard_Real FirstParameter() const Standard_OVERRIDE;
   
   Standard_EXPORT Standard_Real LastParameter() const Standard_OVERRIDE;
diff --git a/tests/bugs/modalg_6/bug27341_312 b/tests/bugs/modalg_6/bug27341_312
index 326496810a..85bcb3d93e 100644
--- a/tests/bugs/modalg_6/bug27341_312
+++ b/tests/bugs/modalg_6/bug27341_312
@@ -23,6 +23,6 @@ build3d result
 fit
 
 checkprops result -l 534.882
-checknbshapes result -vertex 310 -edge 155
+checknbshapes result -vertex 318 -edge 159
 
 checkview -screenshot -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_6/bug27998_1 b/tests/bugs/modalg_6/bug27998_1
new file mode 100644
index 0000000000..c3de713581
--- /dev/null
+++ b/tests/bugs/modalg_6/bug27998_1
@@ -0,0 +1,17 @@
+puts "============"
+puts "OCC27998"
+puts "============"
+puts ""
+######################################################
+# Self-intersection is not detected
+######################################################
+
+restore [locate_data_file bug27998_solid_8.brep] a
+
+set info1 [bopcheck a 9]
+
+if { [regexp "F/F: x6 x6" $info1] != 1 } {
+    puts "Error : bopcheck a works wrong"
+} else {
+    puts "OK: bopcheck a works properly"
+}
\ No newline at end of file
diff --git a/tests/bugs/modalg_6/bug27998_2 b/tests/bugs/modalg_6/bug27998_2
new file mode 100644
index 0000000000..0ee66cddde
--- /dev/null
+++ b/tests/bugs/modalg_6/bug27998_2
@@ -0,0 +1,17 @@
+puts "============"
+puts "OCC27998"
+puts "============"
+puts ""
+######################################################
+# Self-intersection is not detected
+######################################################
+
+restore [locate_data_file bug27998_shape_self-int.brep] a
+
+set info1 [bopcheck a 9]
+
+if { ([regexp "F/F: x18 x18" $info1] != 1) && ([regexp "F/F: x44 x44" $info1] != 1) } {
+    puts "Error : bopcheck a works wrong"
+} else {
+    puts "OK: bopcheck a works properly"
+}
\ No newline at end of file
diff --git a/tests/bugs/modalg_6/bug27998_3 b/tests/bugs/modalg_6/bug27998_3
new file mode 100644
index 0000000000..a73e8d60be
--- /dev/null
+++ b/tests/bugs/modalg_6/bug27998_3
@@ -0,0 +1,23 @@
+puts "============"
+puts "OCC27998"
+puts "============"
+puts ""
+######################################################
+# Self-intersection is not detected
+######################################################
+
+restore [locate_data_file bug20807_coil.brep] cc
+explode cc e
+mkcurve cc cc_1
+trim tc cc 0 6
+mkedge ee tc
+prism a ee 0 0 50
+donly a
+
+set info1 [bopcheck a 9]
+
+if { [regexp "F/F: x0 x0" $info1] != 1 } {
+    puts "Error : bopcheck a works wrong"
+} else {
+    puts "OK: bopcheck a works properly"
+}
\ No newline at end of file