From 99c9a8202179a2dd4178c2f59f8833a2ac1ad96f Mon Sep 17 00:00:00 2001
From: jgv <jgv@opencascade.com>
Date: Sun, 13 Sep 2020 23:17:58 +0300
Subject: [PATCH] 0031735: Modeling Algorithms - BRepOffset_MakeOffset works
 slowly and produces wrong result

Modify method IsPlanar of BRepOffset_MakeOffset: try to make planar all possible faces to simplify the input shape.
---
 dox/upgrade/upgrade.md                   |   4 +
 src/BRepOffset/BRepOffset_MakeOffset.cxx | 258 ++++++++++++++++++++---
 src/BRepOffset/BRepOffset_MakeOffset.hxx |  22 +-
 tests/bugs/modalg_2/bug21261_15          |   8 +-
 tests/bugs/modalg_2/bug5805_1            |   2 +-
 tests/bugs/modalg_2/bug5805_10           |   2 +-
 tests/bugs/modalg_2/bug5805_11           |   2 +-
 tests/bugs/modalg_2/bug5805_12           |   2 +-
 tests/bugs/modalg_2/bug5805_18           |   2 +-
 tests/bugs/modalg_2/bug5805_2            |   2 +-
 tests/bugs/modalg_2/bug5805_22           |   2 +-
 tests/bugs/modalg_2/bug5805_23           |   2 +-
 tests/bugs/modalg_2/bug5805_24           |   2 +-
 tests/bugs/modalg_5/bug25406_1           |   2 +-
 tests/bugs/modalg_5/bug25406_2           |   2 +-
 tests/bugs/modalg_7/bug28656             |   2 -
 tests/bugs/modalg_7/bug31735_1           |  22 ++
 tests/bugs/modalg_7/bug31735_2           |  22 ++
 tests/offset/with_intersect_20/K3        |   5 +-
 tests/offset/with_intersect_20/K9        |   5 +-
 tests/offset/with_intersect_80/K3        |   5 +-
 tests/offset/with_intersect_80/K9        |   5 +-
 22 files changed, 312 insertions(+), 68 deletions(-)
 create mode 100644 tests/bugs/modalg_7/bug31735_1
 create mode 100644 tests/bugs/modalg_7/bug31735_2

diff --git a/dox/upgrade/upgrade.md b/dox/upgrade/upgrade.md
index 6bb7f561ff..dea0a5fb71 100644
--- a/dox/upgrade/upgrade.md
+++ b/dox/upgrade/upgrade.md
@@ -1889,6 +1889,10 @@ Unexpected const-ness of Aspect_Window::DoResize() method has been removed, so t
 
 Enumeration BRepOffset_Type is renamed to ChFiDS_TypeOfConcavity.
 
+@subsection upgrade_750_BRepOffset_MakeOffset change in construction of offset faces
+
+Now by default offset faces of non-planar faces may be planar faces if their originals can be approximated by planes.
+
 @subsection upgrade_750_tkv3d TKV3d/TKService toolkits changes
 
 The following changes could be highlighted while porting:
diff --git a/src/BRepOffset/BRepOffset_MakeOffset.cxx b/src/BRepOffset/BRepOffset_MakeOffset.cxx
index 2c3077f4cd..0020890550 100644
--- a/src/BRepOffset/BRepOffset_MakeOffset.cxx
+++ b/src/BRepOffset/BRepOffset_MakeOffset.cxx
@@ -77,6 +77,7 @@
 #include <GeomAPI_ProjectPointOnCurve.hxx>
 #include <GeomFill_Generator.hxx>
 #include <GeomLib.hxx>
+#include <GeomLib_IsPlanarSurface.hxx>
 #include <gp_Cone.hxx>
 #include <gp_Lin2d.hxx>
 #include <gp_Pnt.hxx>
@@ -281,7 +282,8 @@ static
                      BRepAlgo_Image& theImage);
 
 static
-  Standard_Boolean IsPlanar(const TopoDS_Shape& theS);
+void RemoveSeamAndDegeneratedEdges(const TopoDS_Face& theFace,
+                                   const TopoDS_Face& theOldFace);
 
 static
   Standard_Boolean TrimEdge(TopoDS_Edge& NE,
@@ -599,6 +601,8 @@ myRemoveIntEdges(RemoveIntEdges),
 myDone     (Standard_False)
 {
   myAsDes = new BRepAlgo_AsDes();
+  myIsLinearizationAllowed = Standard_True;
+  
   MakeOffsetShape();
 }
 
@@ -627,6 +631,7 @@ void BRepOffset_MakeOffset::Initialize(const TopoDS_Shape&    S,
   myJoin       = Join;
   myThickening     = Thickening;
   myRemoveIntEdges = RemoveIntEdges;
+  myIsLinearizationAllowed = Standard_True;
   myDone     = Standard_False;
   myIsPerformSewing = Standard_False;
   myIsPlanar = Standard_False;
@@ -646,6 +651,7 @@ void BRepOffset_MakeOffset::Clear()
   myInitOffsetEdge .Clear();
   myImageOffset    .Clear();
   myFaces          .Clear();  
+  myOriginalFaces  .Clear();  
   myFaceOffset     .Clear();
   myAsDes          ->Clear();
   myDone     = Standard_False;
@@ -653,19 +659,24 @@ void BRepOffset_MakeOffset::Clear()
   myResMap.Clear();
 }
 
+//=======================================================================
+//function : AllowLinearization
+//purpose  : 
+//=======================================================================
+
+void BRepOffset_MakeOffset::AllowLinearization(const Standard_Boolean theIsAllowed)
+{
+  myIsLinearizationAllowed = theIsAllowed;
+}
+
 //=======================================================================
 //function : AddFace
 //purpose  : 
 //=======================================================================
 
 void BRepOffset_MakeOffset::AddFace(const TopoDS_Face& F) {
-  myFaces.Add(F);    
-  //-------------
-  // MAJ SD.
-  //-------------
-  myInitOffsetFace.SetRoot (F)  ;    
-  myInitOffsetFace.Bind    (F,F);
-  myImageOffset.SetRoot    (F)  ;  
+
+  myOriginalFaces.Add(F);
 }
 
 //=======================================================================
@@ -676,8 +687,7 @@ void BRepOffset_MakeOffset::AddFace(const TopoDS_Face& F) {
 void BRepOffset_MakeOffset::SetOffsetOnFace(const TopoDS_Face&  F, 
                                             const Standard_Real Off)
 {
-  if ( myFaceOffset.IsBound(F)) myFaceOffset.UnBind(F);
-  myFaceOffset.Bind(F,Off);
+  myFaceOffset.Bind(F, Off);
 }
 
 //=======================================================================
@@ -771,6 +781,50 @@ static void EvalMax(const TopoDS_Shape& S, Standard_Real& Tol)
   }
 }
 
+//=======================================================================
+//function : SetFaces
+//purpose  : 
+//=======================================================================
+
+void BRepOffset_MakeOffset::SetFaces()
+{
+  for (Standard_Integer ii = 1; ii <= myOriginalFaces.Extent(); ii++)
+  {
+    TopoDS_Face aFace = TopoDS::Face(myOriginalFaces(ii));
+    const TopoDS_Shape* aPlanface = myFacePlanfaceMap.Seek(aFace);
+    if (aPlanface)
+      aFace = TopoDS::Face(*aPlanface);
+    
+    myFaces.Add(aFace);    
+    //-------------
+    // MAJ SD.
+    //-------------
+    myInitOffsetFace.SetRoot (aFace)  ;    
+    myInitOffsetFace.Bind    (aFace, aFace);
+    myImageOffset.SetRoot    (aFace)  ;  
+  }
+}
+
+//=======================================================================
+//function : SetFacesWithOffset
+//purpose  : 
+//=======================================================================
+
+void BRepOffset_MakeOffset::SetFacesWithOffset()
+{
+  TopTools_DataMapIteratorOfDataMapOfShapeShape anItmap(myFacePlanfaceMap);
+  for (; anItmap.More(); anItmap.Next())
+  {
+    TopoDS_Face aFace = TopoDS::Face(anItmap.Key());
+    TopoDS_Face aPlanface = TopoDS::Face(anItmap.Value());
+    if (myFaceOffset.IsBound(aFace))
+    {
+      Standard_Real anOffset = myFaceOffset(aFace);
+      myFaceOffset.UnBind(aFace);
+      myFaceOffset.Bind(aPlanface, anOffset);
+    }
+  }
+}
 
 //=======================================================================
 //function : MakeOffsetShape
@@ -781,14 +835,22 @@ void BRepOffset_MakeOffset::MakeOffsetShape()
 {  
   myDone = Standard_False;
   //
+
   // check if shape consists of only planar faces
-  myIsPlanar = IsPlanar(myShape);
+  myIsPlanar = IsPlanar();
+
+  SetFaces();
+  SetFacesWithOffset();
+  
+  BuildFaceComp();
+  
   //------------------------------------------
   // Construction of myShape without caps.
   //------------------------------------------
   if(!myFaces.IsEmpty())
   {
-    RemoveCorks (myShape,myFaces);
+    RemoveCorks (myShape, myOriginalFaces);
+    RemoveCorks (myFaceComp, myFaces);
   }
 
   if (!CheckInputData())
@@ -813,7 +875,7 @@ void BRepOffset_MakeOffset::MakeOffsetShape()
     myAnalyse.SetOffsetValue (myOffset);
     myAnalyse.SetFaceOffsetMap (myFaceOffset);
   }
-  myAnalyse.Perform(myShape,TolAngle);
+  myAnalyse.Perform(myFaceComp,TolAngle);
   //---------------------------------------------------
   // Construction of Offset from preanalysis.
   //---------------------------------------------------  
@@ -1058,7 +1120,7 @@ void BRepOffset_MakeOffset::MakeOffsetFaces(BRepOffset_DataMapOfShapeOffset& the
   //
   Standard_Boolean OffsetOutside = (myOffset > 0.);
   //
-  BRepLib::SortFaces(myShape, aLF);
+  BRepLib::SortFaces(myFaceComp, aLF);
   //
   aItLF.Initialize(aLF);
   for (; aItLF.More(); aItLF.Next()) {
@@ -1146,12 +1208,12 @@ void BRepOffset_MakeOffset::BuildOffsetByInter()
 
   BRepOffset_Inter3d Inter3 (AsDes,Side,myTol);
   // Intersection between parallel faces
-  Inter3.ConnexIntByInt(myShape,MapSF,myAnalyse,MES,Build,Failed,myIsPlanar);
+  Inter3.ConnexIntByInt(myFaceComp,MapSF,myAnalyse,MES,Build,Failed,myIsPlanar);
   // Intersection with caps.
   Inter3.ContextIntByInt(myFaces,ExtentContext,MapSF,myAnalyse,MES,Build,Failed,myIsPlanar);
 
   TopTools_ListOfShape aLFaces;
-  for (Exp.Init(myShape,TopAbs_FACE) ; Exp.More(); Exp.Next())
+  for (Exp.Init(myFaceComp,TopAbs_FACE) ; Exp.More(); Exp.Next())
     aLFaces.Append (Exp.Current());
   for (TopTools_ListOfShape::Iterator it (myAnalyse.NewFaces()); it.More(); it.Next())
     aLFaces.Append (it.Value());
@@ -1174,7 +1236,7 @@ void BRepOffset_MakeOffset::BuildOffsetByInter()
   //Map of edges obtained after FACE-FACE (offsetted) intersection.
   //Key1 is edge trimmed by intersection points with other edges;
   //Item is not-trimmed edge. 
-  if (!TrimEdges(myShape, myOffset, myAnalyse, MapSF, MES, Build, AsDes, AsDes2d, NewEdges, aETrimEInf, anEdgesOrigins))
+  if (!TrimEdges(myFaceComp, myOffset, myAnalyse, MapSF, MES, Build, AsDes, AsDes2d, NewEdges, aETrimEInf, anEdgesOrigins))
   {
     myError = BRepOffset_CannotTrimEdges;
     return;
@@ -1483,7 +1545,7 @@ void BRepOffset_MakeOffset::ReplaceRoots()
 {
   // Replace the artificial faces and edges in InitOffset maps with the original ones.
   TopTools_MapOfShape View;
-  for (TopExp_Explorer anExpF (myShape, TopAbs_EDGE); anExpF.More(); anExpF.Next())
+  for (TopExp_Explorer anExpF (myFaceComp, TopAbs_EDGE); anExpF.More(); anExpF.Next())
   {
     const TopoDS_Shape& aF = anExpF.Current();
     for (TopExp_Explorer anExpE (aF, TopAbs_EDGE); anExpE.More(); anExpE.Next())
@@ -1514,6 +1576,26 @@ void BRepOffset_MakeOffset::ReplaceRoots()
   }
 }
 
+//=======================================================================
+//function : BuildFaceComp
+//purpose  : Make a compound containing actual faces (including planar faces instead of their originals)
+//=======================================================================
+void BRepOffset_MakeOffset::BuildFaceComp()
+{
+  BRep_Builder aBB;
+  aBB.MakeCompound(myFaceComp);
+  TopExp_Explorer anExplo(myShape, TopAbs_FACE);
+  for (; anExplo.More(); anExplo.Next())
+  {
+    TopoDS_Shape aFace = anExplo.Current();
+    TopAbs_Orientation anOr = aFace.Orientation();
+    const TopoDS_Shape* aPlanface = myFacePlanfaceMap.Seek(aFace);
+    if (aPlanface)
+      aFace = *aPlanface;
+    aBB.Add(myFaceComp, aFace.Oriented(anOr));
+  }
+}
+
 //=======================================================================
 //function : BuildOffsetByArc
 //purpose  : 
@@ -1543,7 +1625,7 @@ void BRepOffset_MakeOffset::BuildOffsetByArc()
   ChFiDS_TypeOfConcavity OT = ChFiDS_Convex;
   if (myOffset < 0.) OT = ChFiDS_Concave; 
    
-  for (Exp.Init(myShape,TopAbs_EDGE); Exp.More(); Exp.Next()) {
+  for (Exp.Init(myFaceComp,TopAbs_EDGE); Exp.More(); Exp.Next()) {
     const TopoDS_Edge& E = TopoDS::Edge(Exp.Current());
     if (Done.Add(E)) {
       const TopTools_ListOfShape& Anc = myAnalyse.Ancestors(E);
@@ -1612,7 +1694,7 @@ void BRepOffset_MakeOffset::BuildOffsetByArc()
   Done.Clear();
   TopTools_ListIteratorOfListOfShape it;
 
-  for (Exp.Init(myShape,TopAbs_VERTEX); Exp.More(); Exp.Next()) {
+  for (Exp.Init(myFaceComp,TopAbs_VERTEX); Exp.More(); Exp.Next()) {
     const TopoDS_Vertex& V = TopoDS::Vertex (Exp.Current());
     if (Done.Add(V)) {
       const TopTools_ListOfShape& LA = myAnalyse.Ancestors(V);
@@ -2403,14 +2485,14 @@ void BRepOffset_MakeOffset::Intersection3D(BRepOffset_Inter3d& Inter)
     Inter.CompletInt (OffsetFaces,myInitOffsetFace);
     TopTools_IndexedMapOfShape& NewEdges = Inter.NewEdges();
     if (myJoin == GeomAbs_Intersection) {
-      BRepOffset_Tool::CorrectOrientation (myShape,NewEdges,myAsDes,myInitOffsetFace,myOffset);
+      BRepOffset_Tool::CorrectOrientation (myFaceComp,NewEdges,myAsDes,myInitOffsetFace,myOffset);
     }
   }
   else {
     //--------------------------------
     // Only between neighbor faces.
     //--------------------------------
-    Inter.ConnexIntByArc(OffsetFaces,myShape,myAnalyse,myInitOffsetFace);
+    Inter.ConnexIntByArc(OffsetFaces,myFaceComp,myAnalyse,myInitOffsetFace);
   }
 #ifdef OCCT_DEBUG
   if ( ChronBuild) Clock.Show();
@@ -2592,7 +2674,7 @@ void BRepOffset_MakeOffset::MakeMissingWalls ()
   TopTools_DataMapOfShapeShape MapEF; //Edges of contours: edge + face
   Standard_Real OffsetVal = Abs(myOffset);
 
-  FillContours(myShape, myAnalyse, Contours, MapEF);
+  FillContours(myFaceComp, myAnalyse, Contours, MapEF);
 
   for (Standard_Integer ic = 1; ic <= Contours.Extent(); ic++)
   {
@@ -3200,7 +3282,7 @@ void BRepOffset_MakeOffset::MakeSolid ()
 void BRepOffset_MakeOffset::SelectShells ()
 {
   TopTools_MapOfShape FreeEdges;
-  TopExp_Explorer exp(myShape,TopAbs_EDGE);
+  TopExp_Explorer exp(myFaceComp,TopAbs_EDGE);
   //-------------------------------------------------------------
   // FreeEdges all edges that can have free border in the  
   // parallel shell
@@ -3510,6 +3592,7 @@ void UpdateTolerance (TopoDS_Shape& S,
         Standard_Real aFirst, aLast;
         Handle(Geom_Curve) aCrv = BRep_Tool::Curve(E, aFirst, aLast);
         Standard_Real aMaxDist = ComputeMaxDist(aBAS.Plane(), aCrv, aFirst, aLast);
+        E.Locked (Standard_False);
         B.UpdateEdge(E, aMaxDist);
         isUpdated = Standard_True;
       }
@@ -3532,6 +3615,7 @@ void UpdateTolerance (TopoDS_Shape& S,
             Handle(BRep_TVertex) TV = Handle(BRep_TVertex)::DownCast(V[i].TShape());
             TV->Tolerance(0.);
             BRepCheck_Vertex VertexCorrector(V[i]);
+            V[i].Locked (Standard_False);
             B.UpdateVertex(V[i], VertexCorrector.Tolerance());
             // use the occasion to clean the vertices.
             (TV->ChangePoints()).Clear();
@@ -3656,7 +3740,7 @@ Standard_Boolean BRepOffset_MakeOffset::CheckInputData()
   }
 
   // Connectivity of input shape.
-  if (!IsConnectedShell(myShape))
+  if (!IsConnectedShell(myFaceComp))
   {
     myError = BRepOffset_NotConnectedShell;
     return Standard_False;
@@ -3665,7 +3749,7 @@ Standard_Boolean BRepOffset_MakeOffset::CheckInputData()
   // Normals check and continuity check.
   const Standard_Integer aPntPerDim = 20; // 21 points on each dimension.
   Standard_Real aUmin, aUmax, aVmin, aVmax;
-  TopExp_Explorer anExpSF(myShape, TopAbs_FACE);
+  TopExp_Explorer anExpSF(myFaceComp, TopAbs_FACE);
   NCollection_Map<Handle(TopoDS_TShape)> aPresenceMap;
   TopLoc_Location L;
   gp_Pnt2d aPnt2d;
@@ -4490,17 +4574,127 @@ Standard_Boolean GetSubShapes(const TopoDS_Shape& theShape,
 //function : IsPlanar
 //purpose  : Checks if all the faces of the shape are planes
 //=======================================================================
-Standard_Boolean IsPlanar(const TopoDS_Shape& theS)
+Standard_Boolean BRepOffset_MakeOffset::IsPlanar()
 {
-  TopExp_Explorer aExp(theS, TopAbs_FACE);
-  for (; aExp.More(); aExp.Next()) {
+  Standard_Boolean aIsNonPlanarFound = Standard_False;
+  BRep_Builder aBB;
+  
+  TopExp_Explorer aExp(myShape, TopAbs_FACE);
+  for (; aExp.More(); aExp.Next())
+  {
     const TopoDS_Face& aF = *(TopoDS_Face*)&aExp.Current();
     BRepAdaptor_Surface aBAS(aF, Standard_False);
-    if (aBAS.GetType() != GeomAbs_Plane) {
-      break;
+    if (aBAS.GetType() == GeomAbs_Plane)
+      continue;
+    
+    if (myIsLinearizationAllowed)
+    {
+      //define the toleance
+      Standard_Real aTolForFace = BRep_Tool::Tolerance(aF);
+
+      //try to linearize
+      Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aF);
+      GeomLib_IsPlanarSurface aPlanarityChecker(aSurf, Precision::Confusion());
+      if (aPlanarityChecker.IsPlanar())
+      {
+        gp_Pln aPln = aPlanarityChecker.Plan();
+        Handle(Geom_Plane) aPlane = new Geom_Plane(aPln);
+        TopoDS_Face aPlanarFace;
+        aBB.MakeFace(aPlanarFace, aPlane, aTolForFace);
+        TopoDS_Face aFaceForward = aF;
+        aFaceForward.Orientation(TopAbs_FORWARD);
+        TopoDS_Iterator anItFace(aFaceForward);
+        for (; anItFace.More(); anItFace.Next())
+        {
+          const TopoDS_Shape& aWire = anItFace.Value();
+          aBB.Add(aPlanarFace, aWire);
+        }
+        RemoveSeamAndDegeneratedEdges(aPlanarFace, aFaceForward);
+        myFacePlanfaceMap.Bind(aF, aPlanarFace);
+        if (myFaces.Contains(aF))
+        {
+          myFaces.RemoveKey(aF);
+          myFaces.Add(aPlanarFace);
+        }
+      }
+      else
+        aIsNonPlanarFound = Standard_True;
     }
+    else
+      aIsNonPlanarFound = Standard_True;
+  }
+  
+  return (!aIsNonPlanarFound);
+}
+
+//=======================================================================
+//function : RemoveSeamAndDegeneratedEdges
+//purpose  : Removes useless seam and degenerated edges from a face that becomes planar
+//=======================================================================
+void RemoveSeamAndDegeneratedEdges(const TopoDS_Face& theFace,
+                                   const TopoDS_Face& theOldFace)
+{
+  TopoDS_Face aFace = theFace;
+  aFace.Orientation(TopAbs_FORWARD);
+
+  Standard_Boolean aIsDegOrSeamFound = Standard_False;
+  TopTools_SequenceOfShape aEseq;
+  TopExp_Explorer anExplo(aFace, TopAbs_EDGE);
+  for (; anExplo.More(); anExplo.Next())
+  {
+    const TopoDS_Edge& anEdge = TopoDS::Edge(anExplo.Current());
+    if (BRep_Tool::Degenerated(anEdge) ||
+        BRepTools::IsReallyClosed(anEdge, theOldFace))
+      aIsDegOrSeamFound = Standard_True;
+    else
+      aEseq.Append(anEdge);
+  }
+
+  if (!aIsDegOrSeamFound)
+    return;
+
+  //Reconstruct wires
+  BRep_Builder aBB;
+  TopTools_ListOfShape aWlist;
+  TopoDS_Iterator anItFace(aFace);
+  for (; anItFace.More(); anItFace.Next())
+    aWlist.Append(anItFace.Value());
+
+  aFace.Free(Standard_True);
+  TopTools_ListIteratorOfListOfShape anItl(aWlist);
+  for (; anItl.More(); anItl.Next())
+    aBB.Remove(aFace, anItl.Value());
+
+  while (!aEseq.IsEmpty())
+  {
+    TopoDS_Wire aNewWire;
+    aBB.MakeWire(aNewWire);
+    TopoDS_Edge aCurEdge = TopoDS::Edge(aEseq(1));
+    aBB.Add(aNewWire, aCurEdge);
+    aEseq.Remove(1);
+    TopoDS_Vertex aFirstVertex, aCurVertex;
+    TopExp::Vertices(aCurEdge, aFirstVertex, aCurVertex, Standard_True); //with orientation
+    while (!aCurVertex.IsSame(aFirstVertex))
+    {
+      TopoDS_Vertex aV1, aV2;
+      Standard_Integer ind;
+      for (ind = 1; ind <= aEseq.Length(); ind++)
+      {
+        aCurEdge = TopoDS::Edge(aEseq(ind));
+        TopExp::Vertices(aCurEdge, aV1, aV2, Standard_True); //with orientation
+        if (aV1.IsSame(aCurVertex))
+          break;
+      }
+      if (ind > aEseq.Length()) //error occured: wire is not closed
+        break;
+      
+      aBB.Add(aNewWire, aCurEdge);
+      aEseq.Remove(ind);
+      aCurVertex = aV2;
+    }
+
+    aBB.Add(aFace, aNewWire);
   }
-  return !aExp.More();
 }
 
 //=======================================================================
diff --git a/src/BRepOffset/BRepOffset_MakeOffset.hxx b/src/BRepOffset/BRepOffset_MakeOffset.hxx
index b46d88f587..d7de2eaa7d 100644
--- a/src/BRepOffset/BRepOffset_MakeOffset.hxx
+++ b/src/BRepOffset/BRepOffset_MakeOffset.hxx
@@ -23,6 +23,7 @@
 
 #include <Standard_Real.hxx>
 #include <TopoDS_Shape.hxx>
+#include <TopoDS_Compound.hxx>
 #include <BRepOffset_Mode.hxx>
 #include <Standard_Boolean.hxx>
 #include <GeomAbs_JoinType.hxx>
@@ -50,7 +51,6 @@ public:
 
   DEFINE_STANDARD_ALLOC
 
-  
   Standard_EXPORT BRepOffset_MakeOffset();
   
   Standard_EXPORT BRepOffset_MakeOffset(const TopoDS_Shape& S,
@@ -75,6 +75,9 @@ public:
   
   Standard_EXPORT void Clear();
   
+  //! Changes the flag allowing the linearization
+  Standard_EXPORT void AllowLinearization (const Standard_Boolean theIsAllowed);
+  
   //! Add Closing Faces,  <F>  has to be  in  the initial
   //! shape S.
   Standard_EXPORT void AddFace (const TopoDS_Face& F);
@@ -143,6 +146,19 @@ protected:
 
 private:
 
+  //! Check if shape consists of only planar faces
+  //! If <myIsLinearizationAllowed> is TRUE, try to approximate images of faces
+  //! by planar faces
+  Standard_EXPORT Standard_Boolean IsPlanar();
+  
+  //! Set the faces that are to be removed
+  Standard_EXPORT void SetFaces();
+  
+  //! Set the faces with special value of offset
+  Standard_EXPORT void SetFacesWithOffset();
+  
+  Standard_EXPORT void BuildFaceComp();
+  
   Standard_EXPORT void BuildOffsetByArc();
   
   Standard_EXPORT void BuildOffsetByInter();
@@ -216,7 +232,9 @@ private:
   Standard_Real myOffset;
   Standard_Real myTol;
   TopoDS_Shape myShape;
+  TopoDS_Compound myFaceComp;
   BRepOffset_Mode myMode;
+  Standard_Boolean myIsLinearizationAllowed;
   Standard_Boolean myInter;
   Standard_Boolean mySelfInter;
   GeomAbs_JoinType myJoin;
@@ -224,6 +242,7 @@ private:
   Standard_Boolean myRemoveIntEdges;
   TopTools_DataMapOfShapeReal myFaceOffset;
   TopTools_IndexedMapOfShape myFaces;
+  TopTools_IndexedMapOfShape myOriginalFaces;
   BRepOffset_Analyse myAnalyse;
   TopoDS_Shape myOffsetShape;
   BRepAlgo_Image myInitOffsetFace;
@@ -237,6 +256,7 @@ private:
   Standard_Boolean myIsPerformSewing; // Handle bad walls in thicksolid mode.
   Standard_Boolean myIsPlanar;
   TopoDS_Shape myBadShape;
+  TopTools_DataMapOfShapeShape myFacePlanfaceMap;
   TopTools_ListOfShape myGenerated;
   TopTools_MapOfShape myResMap;
 };
diff --git a/tests/bugs/modalg_2/bug21261_15 b/tests/bugs/modalg_2/bug21261_15
index 47ba72d1c2..af31c17395 100755
--- a/tests/bugs/modalg_2/bug21261_15
+++ b/tests/bugs/modalg_2/bug21261_15
@@ -1,7 +1,3 @@
-puts "TODO OCC25916 ALL: ERROR. C0 continuity of input data."
-puts "TODO OCC26556 ALL: Error: The command cannot be built"
-puts "TODO OCC26556 ALL: Tcl Exception: Error : command \\\"nbshapes result\\\" gives an empty result"
-puts "TODO OCC25916 ALL: TEST INCOMPLETE"
 puts "========"
 puts "OCC21261"
 puts "========"
@@ -16,8 +12,8 @@ restore [locate_data_file OCC21261-2137_bss1_crash_C0.brep] s
 
 thickshell result s -5
 
-checkprops result -s 27432.4 
-checknbshapes result -vertex 4 -edge 6 -wire 6 -face 4 -shell 1 -solid 1 -compsolid 0 -compound 0 -shape 22
+checkprops result -s 31416.7
+checknbshapes result -t -wire 6 -face 6 -shell 1 -solid 1
 checkshape result
 
 vinit
diff --git a/tests/bugs/modalg_2/bug5805_1 b/tests/bugs/modalg_2/bug5805_1
index 1e9a95f5a2..a518ae6bb0 100755
--- a/tests/bugs/modalg_2/bug5805_1
+++ b/tests/bugs/modalg_2/bug5805_1
@@ -37,5 +37,5 @@ checkmaxtol result -min_tol 1.
 checkprops result -s 981.941 
 checkshape result
 
-checknbshapes result -vertex 6 -edge 10 -wire 8 -face 6 -shell 1 -solid 1 -compsolid 0 -compound 0 -shape 32
+checknbshapes result -t -wire 8 -face 6 -shell 1 -solid 1
 checkview -display result -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_2/bug5805_10 b/tests/bugs/modalg_2/bug5805_10
index b7162ec186..b4be1aa824 100755
--- a/tests/bugs/modalg_2/bug5805_10
+++ b/tests/bugs/modalg_2/bug5805_10
@@ -32,7 +32,7 @@ catch { OFFSETSHAPE $distance {s_2} $calcul $type }
 checkprops result -s 1065.08
 checkshape result
 
-checknbshapes result -vertex 3 -edge 5 -wire 6 -face 5 -shell 1 -solid 1 -compsolid 0 -compound 0 -shape 21
+checknbshapes result -t -wire 6 -face 5 -shell 1 -solid 1
 
 set index [lsearch [whatis s] Closed]
 if {$index == -1} {
diff --git a/tests/bugs/modalg_2/bug5805_11 b/tests/bugs/modalg_2/bug5805_11
index eb7c4f5cc8..5486e9679c 100755
--- a/tests/bugs/modalg_2/bug5805_11
+++ b/tests/bugs/modalg_2/bug5805_11
@@ -31,7 +31,7 @@ catch { OFFSETSHAPE $distance {s_3} $calcul $type }
 checkprops result -s 1065.08
 checkshape result
 
-checknbshapes result -vertex 3 -edge 5 -wire 6 -face 5 -shell 1 -solid 1 -compsolid 0 -compound 0 -shape 21
+checknbshapes result -t -wire 6 -face 5 -shell 1 -solid 1
 
 set index [lsearch [whatis s] Closed]
 if {$index == -1} {
diff --git a/tests/bugs/modalg_2/bug5805_12 b/tests/bugs/modalg_2/bug5805_12
index 716cdaf68d..ac9a7592ae 100755
--- a/tests/bugs/modalg_2/bug5805_12
+++ b/tests/bugs/modalg_2/bug5805_12
@@ -32,7 +32,7 @@ catch { OFFSETSHAPE $distance {s_2 s_3} $calcul $type }
 checkprops result -s 1006.59
 checkshape result
 
-checknbshapes result -vertex 3 -edge 5 -wire 6 -face 4 -shell 1 -solid 1 -compsolid 0 -compound 0 -shape 20
+checknbshapes result -t -wire 6 -face 4 -shell 1 -solid 1
 
 set index [lsearch [whatis s] Closed]
 if {$index == -1} {
diff --git a/tests/bugs/modalg_2/bug5805_18 b/tests/bugs/modalg_2/bug5805_18
index e1841163ed..554fb86e4e 100755
--- a/tests/bugs/modalg_2/bug5805_18
+++ b/tests/bugs/modalg_2/bug5805_18
@@ -49,5 +49,5 @@ if {$index == -1} {
 }
 
 checkshape result
-checknbshapes result -vertex 4 -edge 5 -wire 5 -face 5 -shell 2 -solid 1 -compsolid 0 -compound 0 -shape 22
+checknbshapes result -t -wire 5 -face 5 -shell 2 -solid 1
 checkview -display result -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_2/bug5805_2 b/tests/bugs/modalg_2/bug5805_2
index 677cb7b8c7..3feecda49b 100755
--- a/tests/bugs/modalg_2/bug5805_2
+++ b/tests/bugs/modalg_2/bug5805_2
@@ -33,5 +33,5 @@ checkmaxtol result -min_tol 1.
 checkprops result -s 1006.59
 checkshape result
 
-checknbshapes result -vertex 3 -edge 5 -wire 6 -face 4 -shell 1 -solid 1 -compsolid 0 -compound 0 -shape 20
+checknbshapes result -t -wire 6 -face 4 -shell 1 -solid 1
 checkview -display result -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_2/bug5805_22 b/tests/bugs/modalg_2/bug5805_22
index 1b44952eb3..fb65926458 100755
--- a/tests/bugs/modalg_2/bug5805_22
+++ b/tests/bugs/modalg_2/bug5805_22
@@ -33,7 +33,7 @@ catch { OFFSETSHAPE $distance {s_3} $calcul $type }
 checkprops result -s 552.913
 checkshape result
 
-checknbshapes result -vertex 3 -edge 5 -wire 6 -face 5 -shell 1 -solid 1 -compsolid 0 -compound 0 -shape 21
+checknbshapes result -t -wire 6 -face 5 -shell 1 -solid 1
 
 set index [lsearch [whatis s] Closed]
 if {$index == -1} {
diff --git a/tests/bugs/modalg_2/bug5805_23 b/tests/bugs/modalg_2/bug5805_23
index 4c32116e71..a45e8a9e80 100755
--- a/tests/bugs/modalg_2/bug5805_23
+++ b/tests/bugs/modalg_2/bug5805_23
@@ -33,7 +33,7 @@ catch { OFFSETSHAPE $distance {s_2} $calcul $type }
 checkprops result -s 552.913
 checkshape result
 
-checknbshapes result -vertex 3 -edge 5 -wire 6 -face 5 -shell 1 -solid 1 -compsolid 0 -compound 0 -shape 21
+checknbshapes result -t -wire 6 -face 5 -shell 1 -solid 1
 
 set index [lsearch [whatis s] Closed]
 if {$index == -1} {
diff --git a/tests/bugs/modalg_2/bug5805_24 b/tests/bugs/modalg_2/bug5805_24
index 4c76df6fde..ef465cd0b7 100755
--- a/tests/bugs/modalg_2/bug5805_24
+++ b/tests/bugs/modalg_2/bug5805_24
@@ -33,7 +33,7 @@ catch { OFFSETSHAPE $distance {s_3 s_2} $calcul $type }
 checkprops result -s 540.231
 checkshape result
 
-checknbshapes result -vertex 3 -edge 5 -wire 6 -face 4 -shell 1 -solid 1 -compsolid 0 -compound 0 -shape 20
+checknbshapes result -t -wire 6 -face 4 -shell 1 -solid 1
 
 set index [lsearch [whatis s] Closed]
 if {$index == -1} {
diff --git a/tests/bugs/modalg_5/bug25406_1 b/tests/bugs/modalg_5/bug25406_1
index 01af589f09..499a5be539 100644
--- a/tests/bugs/modalg_5/bug25406_1
+++ b/tests/bugs/modalg_5/bug25406_1
@@ -14,7 +14,7 @@ checkprops result -l 1875.31
 checkshape result 
 checksection result
 
-checknbshapes result -vertex 2 -edge 4 -wire 1 -face 1 -shell 1 -solid 0 -compsolid 0 -compound 0 -shape 9
+checknbshapes result -t -wire 1 -face 1 -shell 1
 smallview
 fit
 checkview -screenshot -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_5/bug25406_2 b/tests/bugs/modalg_5/bug25406_2
index 9ed3779a4b..c4fa878490 100644
--- a/tests/bugs/modalg_5/bug25406_2
+++ b/tests/bugs/modalg_5/bug25406_2
@@ -14,7 +14,7 @@ checkprops result -l 1875.31
 checkshape result 
 checksection result
 
-checknbshapes result -vertex 2 -edge 4 -wire 1 -face 1 -shell 1 -solid 0 -compsolid 0 -compound 0 -shape 9
+checknbshapes result -t -wire 1 -face 1 -shell 1
 smallview
 fit
 checkview -screenshot -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_7/bug28656 b/tests/bugs/modalg_7/bug28656
index fe6c82fa9e..a644654657 100755
--- a/tests/bugs/modalg_7/bug28656
+++ b/tests/bugs/modalg_7/bug28656
@@ -1,5 +1,3 @@
-puts "TODO OCC28656 ALL: TopoDS_LockedShape: BRep_Builder::UpdateEdge"
-
 puts "========"
 puts "OCC28656"
 puts "========"
diff --git a/tests/bugs/modalg_7/bug31735_1 b/tests/bugs/modalg_7/bug31735_1
new file mode 100644
index 0000000000..8f09145b89
--- /dev/null
+++ b/tests/bugs/modalg_7/bug31735_1
@@ -0,0 +1,22 @@
+puts "======================================================================"
+puts "OCC31735: BRepOffset_MakeOffset works slowly and produces wrong result"
+puts "======================================================================"
+puts ""
+
+restore [locate_data_file bug31735_1.brep] a
+explode a
+thickshell result a_1 0.02 i
+
+checkshape result
+
+checknbshapes result -t -wire 56 -face 56 -shell 2 -solid 1
+
+set tolres [checkmaxtol result]
+
+if { ${tolres} > 0.001001} {
+   puts "Error: bad tolerance of result"
+}
+
+checkview -display result -2d -path ${imagedir}/${test_image}.png
+
+puts "TEST COMPLETED"
\ No newline at end of file
diff --git a/tests/bugs/modalg_7/bug31735_2 b/tests/bugs/modalg_7/bug31735_2
new file mode 100644
index 0000000000..00cddc23fb
--- /dev/null
+++ b/tests/bugs/modalg_7/bug31735_2
@@ -0,0 +1,22 @@
+puts "======================================================================"
+puts "OCC31735: BRepOffset_MakeOffset works slowly and produces wrong result"
+puts "======================================================================"
+puts ""
+
+restore [locate_data_file bug31735_2.brep] a
+explode a
+thickshell result a_1 -0.1 i
+
+checkshape result
+
+checknbshapes result -t -wire 18 -face 18 -shell 2 -solid 1
+
+set tolres [checkmaxtol result]
+
+if { ${tolres} > 0.5} {
+   puts "Error: bad tolerance of result"
+}
+
+checkview -display result -2d -path ${imagedir}/${test_image}.png
+
+puts "TEST COMPLETED"
\ No newline at end of file
diff --git a/tests/offset/with_intersect_20/K3 b/tests/offset/with_intersect_20/K3
index c432d752b7..d25391e28a 100644
--- a/tests/offset/with_intersect_20/K3
+++ b/tests/offset/with_intersect_20/K3
@@ -1,7 +1,4 @@
-puts "TODO OCC26528 All: ERROR. Degenerated normal on input data."
-puts "TODO OCC26528 All: Error : command \\\"nbshapes result\\\" gives an empty result"
-puts "TODO OCC26528 All:TEST INCOMPLETE"
 restore [locate_data_file bug26663_test_offset_K3.brep] s
 OFFSETSHAPE ${off_param} {} ${calcul} ${type}
-checknbshapes result -ref [lrange [nbshapes s] 8 19]
+checknbshapes result -t -face 6 -shell 1
 
diff --git a/tests/offset/with_intersect_20/K9 b/tests/offset/with_intersect_20/K9
index eeb5371fdb..38f8143d25 100644
--- a/tests/offset/with_intersect_20/K9
+++ b/tests/offset/with_intersect_20/K9
@@ -1,7 +1,4 @@
-puts "TODO OCC26528 All: ERROR. Degenerated normal on input data."
-puts "TODO OCC26528 All: Error : command \\\"nbshapes result\\\" gives an empty result"
-puts "TODO OCC26528 All:TEST INCOMPLETE"
 restore [locate_data_file bug26663_test_offset_K9.brep] s
 OFFSETSHAPE ${off_param} {} ${calcul} ${type}
-checknbshapes result -ref [lrange [nbshapes s] 8 19]
+checknbshapes result -t -face 12 -shell 1
 
diff --git a/tests/offset/with_intersect_80/K3 b/tests/offset/with_intersect_80/K3
index c432d752b7..d25391e28a 100644
--- a/tests/offset/with_intersect_80/K3
+++ b/tests/offset/with_intersect_80/K3
@@ -1,7 +1,4 @@
-puts "TODO OCC26528 All: ERROR. Degenerated normal on input data."
-puts "TODO OCC26528 All: Error : command \\\"nbshapes result\\\" gives an empty result"
-puts "TODO OCC26528 All:TEST INCOMPLETE"
 restore [locate_data_file bug26663_test_offset_K3.brep] s
 OFFSETSHAPE ${off_param} {} ${calcul} ${type}
-checknbshapes result -ref [lrange [nbshapes s] 8 19]
+checknbshapes result -t -face 6 -shell 1
 
diff --git a/tests/offset/with_intersect_80/K9 b/tests/offset/with_intersect_80/K9
index eeb5371fdb..38f8143d25 100644
--- a/tests/offset/with_intersect_80/K9
+++ b/tests/offset/with_intersect_80/K9
@@ -1,7 +1,4 @@
-puts "TODO OCC26528 All: ERROR. Degenerated normal on input data."
-puts "TODO OCC26528 All: Error : command \\\"nbshapes result\\\" gives an empty result"
-puts "TODO OCC26528 All:TEST INCOMPLETE"
 restore [locate_data_file bug26663_test_offset_K9.brep] s
 OFFSETSHAPE ${off_param} {} ${calcul} ${type}
-checknbshapes result -ref [lrange [nbshapes s] 8 19]
+checknbshapes result -t -face 12 -shell 1