Salome HOME
updated copyright message
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_ShapeTools.cpp
index d1d3abe8b5317f5b03ee1e892e3e19c53f65b07f..3d0c3c65b0f0fa1ab7a2efe51c9e0929629f5da2 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2023  CEA, EDF
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
@@ -21,6 +21,8 @@
 
 #include "GeomAlgoAPI_SketchBuilder.h"
 
+#include <Basics_OCCTVersion.hxx>
+
 #include <GeomAPI_Ax1.h>
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Dir.h>
 #include <GeomAPI_Pnt.h>
 #include <GeomAPI_Wire.h>
 
+#include <Approx_CurvilinearParameter.hxx>
+
 #include <Bnd_Box.hxx>
+
+#include <BRep_Tool.hxx>
 #include <BRep_Builder.hxx>
-#include <BRepAdaptor_Curve.hxx>
 #include <BRepAlgo.hxx>
 #include <BRepAlgo_FaceRestrictor.hxx>
+#include <BRepAdaptor_Curve.hxx>
 #include <BRepBndLib.hxx>
+#include <BRepBuilderAPI_Copy.hxx>
 #include <BRepBuilderAPI_FindPlane.hxx>
 #include <BRepBuilderAPI_MakeEdge.hxx>
 #include <BRepBuilderAPI_MakeFace.hxx>
+#include <BRepBuilderAPI_MakeVertex.hxx>
+#include <BRepBuilderAPI_MakeWire.hxx>
 #include <BRepCheck_Analyzer.hxx>
 #include <BRepExtrema_DistShapeShape.hxx>
 #include <BRepExtrema_ExtCF.hxx>
+#include <BRepExtrema_ShapeProximity.hxx>
 #include <BRepGProp.hxx>
+#include <BRepMesh_IncrementalMesh.hxx>
 #include <BRepTools.hxx>
 #include <BRepTools_WireExplorer.hxx>
 #include <BRepTopAdaptor_FClass2d.hxx>
 #include <BRepClass_FaceClassifier.hxx>
+#include <BRepLib_CheckCurveOnSurface.hxx>
+#include <BRepLProp.hxx>
+
+#include <BOPAlgo_Builder.hxx>
+
+#include <Extrema_GenLocateExtCS.hxx>
+#include <Extrema_GenLocateExtSS.hxx>
+#include <Extrema_GenLocateExtPS.hxx>
+#include <Extrema_LocateExtCC.hxx>
+#include <Extrema_LocateExtPC.hxx>
+
 #include <Geom2d_Curve.hxx>
 #include <Geom2d_Curve.hxx>
-#include <BRepLib_CheckCurveOnSurface.hxx>
-#include <BRep_Tool.hxx>
-#include  <Geom_CylindricalSurface.hxx>
+
+#include <Geom_BSplineCurve.hxx>
+#include <Geom_CylindricalSurface.hxx>
 #include <Geom_Line.hxx>
 #include <Geom_Plane.hxx>
+#include <Geom_RectangularTrimmedSurface.hxx>
+
+#if OCC_VERSION_LARGE < 0x07070000
+#include <GeomAdaptor_HCurve.hxx>
+#else
+#include <GeomAdaptor_Curve.hxx>
+#endif
+
 #include <GeomAPI_ProjectPointOnCurve.hxx>
 #include <GeomAPI_ShapeIterator.h>
+
 #include <GeomLib_IsPlanarSurface.hxx>
 #include <GeomLib_Tool.hxx>
 #include <GeomAPI_IntCS.hxx>
+
 #include <gp_Pln.hxx>
 #include <GProp_GProps.hxx>
+
 #include <IntAna_IntConicQuad.hxx>
 #include <IntAna_Quadric.hxx>
-#include <NCollection_Vector.hxx>
+
 #include <ShapeAnalysis.hxx>
 #include <ShapeAnalysis_Surface.hxx>
-#include <TopoDS_Builder.hxx>
+
+#include <TopoDS.hxx>
 #include <TopoDS_Edge.hxx>
 #include <TopoDS_Face.hxx>
 #include <TopoDS_Shape.hxx>
 #include <TopoDS_Shell.hxx>
 #include <TopoDS_Vertex.hxx>
-#include <TopoDS.hxx>
+#include <TopoDS_Builder.hxx>
+
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
+
 #include <TopTools_ListIteratorOfListOfShape.hxx>
 
+#include <NCollection_Vector.hxx>
 
-#include <BOPAlgo_Builder.hxx>
-#include <BRepBuilderAPI_MakeVertex.hxx>
-#include <TopoDS_Edge.hxx>
+#include <LocalAnalysis_SurfaceContinuity.hxx>
+#include<array>
 
 //==================================================================================================
 static GProp_GProps props(const TopoDS_Shape& theShape)
@@ -110,42 +146,51 @@ static GProp_GProps props(const TopoDS_Shape& theShape)
   return aGProps;
 }
 
+//==================================================================================================
+double GeomAlgoAPI_ShapeTools::length(const std::shared_ptr<GeomAPI_Shape> theShape)
+{
+  GProp_GProps aGProps;
+  if (!theShape.get()) {
+    return 0.0;
+  }
+  const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
+  if (aShape.IsNull()) {
+    return 0.0;
+  }
+
+  BRepGProp::LinearProperties(aShape, aGProps, Standard_True);
+  return  aGProps.Mass();
+}
+
 //==================================================================================================
 double GeomAlgoAPI_ShapeTools::volume(const std::shared_ptr<GeomAPI_Shape> theShape)
 {
-  if(!theShape.get()) {
+  if (!theShape.get()) {
     return 0.0;
   }
   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
-  if(aShape.IsNull()) {
+  if (aShape.IsNull()) {
     return 0.0;
   }
   const Standard_Real anEps = 1.e-6;
-  TopExp_Explorer anExp(aShape, TopAbs_SOLID);
-  if (anExp.More()) { // return volume if there is at least one solid
-    double aVolume = 0.0;
-    for (; anExp.More(); anExp.Next()) {
-      GProp_GProps aGProps;
-      BRepGProp::VolumeProperties(anExp.Current(), aGProps, anEps);
-      aVolume += aGProps.Mass();
-    }
-    return aVolume;
+  double aVolume = 0.0;
+  for (TopExp_Explorer anExp(aShape, TopAbs_SOLID); anExp.More(); anExp.Next()) {
+    GProp_GProps aGProps;
+    BRepGProp::VolumeProperties(anExp.Current(), aGProps, anEps);
+    aVolume += aGProps.Mass();
   }
-  // return surfaces area
-  GProp_GProps aGProps;
-  BRepGProp::SurfaceProperties(aShape, aGProps, anEps);
-  return aGProps.Mass();
+  return aVolume;
 }
 
 //==================================================================================================
 double GeomAlgoAPI_ShapeTools::area (const std::shared_ptr<GeomAPI_Shape> theShape)
 {
   GProp_GProps aGProps;
-  if(!theShape.get()) {
+  if (!theShape.get()) {
     return 0.0;
   }
   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
-  if(aShape.IsNull()) {
+  if (aShape.IsNull()) {
     return 0.0;
   }
   const Standard_Real anEps = 1.e-6;
@@ -154,20 +199,119 @@ double GeomAlgoAPI_ShapeTools::area (const std::shared_ptr<GeomAPI_Shape> theSha
   return aGProps.Mass();
 }
 
+//==================================================================================================
+bool GeomAlgoAPI_ShapeTools::isContinuousFaces(const GeomShapePtr& theFace1,
+                                               const GeomShapePtr& theFace2,
+                                               const GeomPointPtr& thePoint,
+                                               const double & theAngle,
+                                               std::string& theError)
+{
+
+  #ifdef _DEBUG
+  std::cout << "isContinuousFaces " << std::endl;
+  #endif
+
+  if (!thePoint.get()) {
+      theError = "isContinuousFaces : An invalid argument";
+      return false;
+  }
+  const gp_Pnt& aPoint = thePoint->impl<gp_Pnt>();
+
+  // Getting base shape.
+  if (!theFace1.get()) {
+    theError = "isContinuousFaces : An invalid argument";
+    return false;
+  }
+
+  TopoDS_Shape aShape1 = theFace1->impl<TopoDS_Shape>();
+
+  if (aShape1.IsNull()) {
+    theError = "isContinuousFaces : An invalid argument";
+    return false;
+  }
+
+  // Getting base shape.
+  if (!theFace2.get()) {
+    theError = "isContinuousFaces : An invalid argument";
+    return false;
+  }
+
+  TopoDS_Shape aShape2 = theFace2->impl<TopoDS_Shape>();
+
+  if (aShape2.IsNull()) {
+    theError = "isContinuousFaces : An invalid argument";
+    return false;
+  }
+
+  TopoDS_Face aFace1 = TopoDS::Face(aShape1);
+  if (aFace1.IsNull()) {
+    theError = "isContinuousFaces : An invalid argument";
+    return false;
+  }
+
+  Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(aFace1);
+  if (aSurf1.IsNull()) {
+    theError = "isContinuousFaces : An invalid surface";
+    return false;
+  }
+
+  ShapeAnalysis_Surface aSAS1(aSurf1);
+  gp_Pnt2d aPointOnFace1 = aSAS1.ValueOfUV(aPoint, Precision::Confusion());
+
+  TopoDS_Face aFace2 = TopoDS::Face(aShape2);
+  if (aFace2.IsNull()) {
+    theError = "isContinuousFaces : An invalid argument";
+    return false;
+  }
+
+  Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(aFace2);
+  if (aSurf2.IsNull()) {
+    theError = "isContinuousFaces : An invalid surface";
+    return false;
+  }
+
+  ShapeAnalysis_Surface aSAS2(aSurf2);
+  gp_Pnt2d aPointOnFace2= aSAS2.ValueOfUV(aPoint, Precision::Confusion());
+
+  bool aRes = false;
+  try {
+    OCC_CATCH_SIGNALS;
+    LocalAnalysis_SurfaceContinuity aLocAnal(aSurf1,
+                                             aPointOnFace1.X(),
+                                             aPointOnFace1.Y(),
+                                             aSurf2,
+                                             aPointOnFace2.X(),
+                                             aPointOnFace2.Y(),
+                                             GeomAbs_Shape::GeomAbs_G1, // Order
+                                             0.001, // EpsNul
+                                             0.001, // EpsC0
+                                             0.001, // EpsC1
+                                             0.001, // EpsC2
+                                             theAngle * M_PI / 180.0); //EpsG1
+    aRes = aLocAnal.IsG1();
+  }
+  catch (Standard_Failure const& anException) {
+    theError = "LocalAnalysis_SurfaceContinuity error :";
+    theError += anException.GetMessageString();
+  }
+
+  return aRes;
+}
+
 //==================================================================================================
 std::shared_ptr<GeomAPI_Pnt>
   GeomAlgoAPI_ShapeTools::centreOfMass(const std::shared_ptr<GeomAPI_Shape> theShape)
 {
   GProp_GProps aGProps;
-  if(!theShape) {
+  if (!theShape) {
     return std::shared_ptr<GeomAPI_Pnt>();
   }
   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
-  if(aShape.IsNull()) {
+  if (aShape.IsNull()) {
     return std::shared_ptr<GeomAPI_Pnt>();
   }
   gp_Pnt aCentre;
-  if(aShape.ShapeType() == TopAbs_VERTEX) {
+  if (aShape.ShapeType() == TopAbs_VERTEX) {
     aCentre = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
   } else {
     aGProps = props(aShape);
@@ -192,17 +336,334 @@ double GeomAlgoAPI_ShapeTools::radius(const std::shared_ptr<GeomAPI_Face>& theCy
 }
 
 //==================================================================================================
-double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1,
-                                               const GeomShapePtr& theShape2)
+namespace {
+
+auto getExtemaDistShape = [](const GeomShapePtr& theShape1,
+    const GeomShapePtr& theShape2) -> BRepExtrema_DistShapeShape
 {
   const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
   const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
 
   BRepExtrema_DistShapeShape aDist(aShape1, aShape2);
   aDist.Perform();
+  return aDist;
+};
+
+static void tessellateShape(const TopoDS_Shape& theShape)
+{
+  Standard_Boolean isTessellate = Standard_False;
+  TopLoc_Location aLoc;
+  for (TopExp_Explorer anExp(theShape, TopAbs_FACE); anExp.More() && !isTessellate; anExp.Next()) {
+    Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation(TopoDS::Face(anExp.Value()), aLoc);
+    isTessellate = aTria.IsNull();
+  }
+  for (TopExp_Explorer anExp(theShape, TopAbs_EDGE); anExp.More() && !isTessellate; anExp.Next()) {
+    Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(TopoDS::Edge(anExp.Value()), aLoc);
+    isTessellate = aPoly.IsNull();
+  }
+
+  if (isTessellate) {
+    BRepMesh_IncrementalMesh aMesher(theShape, 0.1);
+    Standard_ProgramError_Raise_if(!aMesher.IsDone(), "Meshing failed");
+  }
+}
+
+static Standard_Real paramOnCurve(const BRepAdaptor_Curve& theCurve,
+                                  const gp_Pnt&            thePoint,
+                                  const Standard_Real      theTol)
+{
+  Extrema_ExtPC aParamSearch(thePoint,
+                             theCurve,
+                             theCurve.FirstParameter(),
+                             theCurve.LastParameter());
+  if (aParamSearch.IsDone()) {
+    Standard_Integer anIndMin = 0, aNbExt = aParamSearch.NbExt();
+    Standard_Real aSqDistMin = RealLast();
+    for (Standard_Integer i = 1; i <= aNbExt; ++i) {
+      if (aParamSearch.SquareDistance(i) < aSqDistMin) {
+        anIndMin = i;
+        aSqDistMin = aParamSearch.SquareDistance(i);
+      }
+    }
+    if (anIndMin != 0 && aSqDistMin <= theTol * theTol)
+      return aParamSearch.Point(anIndMin).Parameter();
+  }
+  return 0.5 * (theCurve.FirstParameter() + theCurve.LastParameter());
+}
+
+static void paramsOnSurf(const BRepAdaptor_Surface& theSurf,
+                         const gp_Pnt&              thePoint,
+                         const Standard_Real        theTol,
+                         Standard_Real&             theU,
+                         Standard_Real&             theV)
+{
+  Extrema_ExtPS aParamSearch(thePoint, theSurf, Precision::PConfusion(), Precision::PConfusion());
+  if (aParamSearch.IsDone()) {
+    Standard_Integer anIndMin = 0, aNbExt = aParamSearch.NbExt();
+    Standard_Real aSqDistMin = RealLast();
+    for (Standard_Integer i = 1; i <= aNbExt; ++i) {
+      if (aParamSearch.SquareDistance(i) < aSqDistMin) {
+        anIndMin = i;
+        aSqDistMin = aParamSearch.SquareDistance(i);
+      }
+    }
+    if (anIndMin != 0 && aSqDistMin <= theTol * theTol)
+      return aParamSearch.Point(anIndMin).Parameter(theU, theV);
+  }
+  theU = 0.5 * (theSurf.FirstUParameter() + theSurf.LastUParameter());
+  theV = 0.5 * (theSurf.FirstVParameter() + theSurf.LastVParameter());
+}
+
+static Standard_Real extremaEE(const TopoDS_Edge& theEdge1,
+                               const TopoDS_Edge& theEdge2,
+                               const gp_Pnt&      thePoint1,
+                               const gp_Pnt&      thePoint2)
+{
+  BRepAdaptor_Curve aCurve1(theEdge1);
+  BRepAdaptor_Curve aCurve2(theEdge2);
+
+  Standard_Real aU1 = paramOnCurve(aCurve1, thePoint1, BRep_Tool::Tolerance(theEdge1));
+  Standard_Real aU2 = paramOnCurve(aCurve2, thePoint2, BRep_Tool::Tolerance(theEdge2));
+
+  Standard_Real aValue = -1.0;
+  Extrema_LocateExtCC anExtr(aCurve1, aCurve2, aU1, aU2);
+  if (anExtr.IsDone() && aValue > Precision::Confusion())
+    aValue = Sqrt(anExtr.SquareDistance());
+  return aValue;
+}
+
+static Standard_Real extremaPE(const gp_Pnt&      thePoint,
+                               const TopoDS_Edge& theEdge,
+                               gp_Pnt&            thePointOnEdge)
+{
+  BRepAdaptor_Curve aCurve (theEdge);
+
+  TopLoc_Location aLoc;
+  Standard_Real aTol = BRep_Tool::Tolerance(theEdge);
+  Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D (theEdge, aLoc);
+  if (!aPoly.IsNull())
+    aTol = Max (aTol, aPoly->Deflection());
+
+  Standard_Real aParam = paramOnCurve (aCurve, thePointOnEdge, 2*aTol);
+
+  Standard_Real aValue = -1.0;
+  Extrema_LocateExtPC anExtr (thePoint, aCurve, aParam, Precision::PConfusion());
+  if (anExtr.IsDone())
+  {
+    aValue = Sqrt(anExtr.SquareDistance());
+
+    Extrema_POnCurv aPointOnCurve = anExtr.Point();
+    thePointOnEdge = aPointOnCurve.Value();
+  }
+  return aValue;
+}
+  
+static Standard_Real extremaPF(const gp_Pnt&      thePoint,
+                               const TopoDS_Face& theFace,
+                               gp_Pnt&            thePointOnFace)
+{
+  BRepAdaptor_Surface aSurf (theFace);
+
+  TopLoc_Location aLoc;
+  Standard_Real aTol = BRep_Tool::Tolerance(theFace);
+  Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation (theFace, aLoc);
+  if (!aTria.IsNull())
+    aTol = Max (aTol, aTria->Deflection());
+
+  Standard_Real aU, aV;
+  paramsOnSurf(aSurf, thePointOnFace, 2*aTol, aU, aV);
+
+  Standard_Real aValue = -1.0;
+  Extrema_GenLocateExtPS anExtr (aSurf);
+  anExtr.Perform (thePoint, aU, aV);
+  if (anExtr.IsDone())
+  {
+    aValue = Sqrt(anExtr.SquareDistance());
+
+    Extrema_POnSurf aPointOnSurf = anExtr.Point();
+    thePointOnFace = aPointOnSurf.Value();
+  }
+  return aValue;
+}
+
+static Standard_Real extremaEF(const TopoDS_Edge& theEdge,
+                               const TopoDS_Face& theFace,
+                               const gp_Pnt&      thePonE,
+                               const gp_Pnt&      thePonF)
+{
+  BRepAdaptor_Curve aCurve(theEdge);
+  BRepAdaptor_Surface aSurf(theFace);
+
+  Standard_Real aP = paramOnCurve(aCurve, thePonE, BRep_Tool::Tolerance(theEdge));
+  Standard_Real aU, aV;
+  paramsOnSurf(aSurf, thePonF, BRep_Tool::Tolerance(theFace), aU, aV);
+
+  Standard_Real aValue = -1.0;
+  Extrema_GenLocateExtCS anExtr(aCurve, aSurf, aP, aU, aV, Precision::PConfusion(), Precision::PConfusion());
+  if (anExtr.IsDone() && aValue > Precision::Confusion())
+    aValue = Sqrt(anExtr.SquareDistance());
+  return aValue;
+}
+
+static Standard_Real extremaFF(const TopoDS_Face& theFace1,
+                               const TopoDS_Face& theFace2,
+                               const gp_Pnt&      thePoint1,
+                               const gp_Pnt&      thePoint2)
+{
+  BRepAdaptor_Surface aSurf1(theFace1);
+  BRepAdaptor_Surface aSurf2(theFace2);
+
+  Standard_Real aU1, aV1;
+  paramsOnSurf(aSurf1, thePoint1, BRep_Tool::Tolerance(theFace1), aU1, aV1);
+  Standard_Real aU2, aV2;
+  paramsOnSurf(aSurf2, thePoint2, BRep_Tool::Tolerance(theFace2), aU2, aV2);
+
+  Standard_Real aValue = -1.0;
+  Extrema_GenLocateExtSS anExtr(aSurf1, aSurf2, aU1, aV1, aU2, aV2, Precision::PConfusion(), Precision::PConfusion());
+  if (anExtr.IsDone() && aValue > Precision::Confusion())
+    aValue = Sqrt(anExtr.SquareDistance());
+  return aValue;
+}
+
+} // namespace
+
+double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1,
+                                               const GeomShapePtr& theShape2)
+{
+  BRepExtrema_DistShapeShape aDist = getExtemaDistShape(theShape1, theShape2);
+  return aDist.IsDone() ? aDist.Value() : Precision::Infinite();
+}
+
+double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1,
+                                               const GeomShapePtr& theShape2,
+                                               std::array<double, 3> & fromShape1To2)
+{
+  BRepExtrema_DistShapeShape aDist = getExtemaDistShape(theShape1, theShape2);
+  const auto & pt1 = aDist.PointOnShape1(1);
+  const auto & pt2 = aDist.PointOnShape2(1) ;
+  fromShape1To2[0] = pt2.X() - pt1.X();
+  fromShape1To2[1] = pt2.Y() - pt1.Y();
+  fromShape1To2[2] = pt2.Z() - pt1.Z();
   return aDist.IsDone() ? aDist.Value() : Precision::Infinite();
 }
 
+//==================================================================================================
+double GeomAlgoAPI_ShapeTools::shapeProximity(const GeomShapePtr& theShape1,
+                                              const GeomShapePtr& theShape2)
+{
+  double aResult = -1.0;
+  if (!theShape1.get() || !theShape2.get())
+    return aResult;
+
+  const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
+  const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
+
+  TopAbs_ShapeEnum aType1 = aShape1.ShapeType();
+  TopAbs_ShapeEnum aType2 = aShape2.ShapeType();
+
+  // tessellate shapes if there is no mesh exists
+  tessellateShape(aShape1);
+  tessellateShape(aShape2);
+
+  BRepExtrema_ShapeProximity aDist (aShape1, aShape2);
+  aDist.Perform();
+  if (aDist.IsDone()) {
+    aResult = aDist.Proximity();
+
+    // refine the result
+    gp_Pnt aPnt1 = aDist.ProximityPoint1();
+    gp_Pnt aPnt2 = aDist.ProximityPoint2();
+
+    BRepExtrema_ProximityDistTool::ProxPnt_Status aStatus1 = aDist.ProxPntStatus1();
+    BRepExtrema_ProximityDistTool::ProxPnt_Status aStatus2 = aDist.ProxPntStatus2();
+
+    double aValue = -1.0;
+
+    if (aType1 == TopAbs_EDGE)
+    {
+      if (aType2 == TopAbs_EDGE)
+      {
+        if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+            aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaEE(TopoDS::Edge(aShape1), TopoDS::Edge(aShape2), aPnt1, aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaPE(aPnt1, TopoDS::Edge(aShape2), aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
+        {
+          aValue = extremaPE(aPnt2, TopoDS::Edge(aShape1), aPnt1);
+        }
+      }
+      else if (aType2 == TopAbs_FACE)
+      {
+        if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+            aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaEF(TopoDS::Edge(aShape1), TopoDS::Face(aShape2), aPnt1, aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaPF(aPnt1, TopoDS::Face(aShape2), aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
+        {
+          aValue = extremaPE(aPnt2, TopoDS::Edge(aShape1), aPnt1);
+        }
+      }
+    }
+    else if (aType1 == TopAbs_FACE)
+    {
+      if (aType2 == TopAbs_EDGE)
+      {
+        if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+            aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaEF(TopoDS::Edge(aShape2), TopoDS::Face(aShape1), aPnt2, aPnt1);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaPE(aPnt1, TopoDS::Edge(aShape2), aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
+        {
+          aValue = extremaPF(aPnt2, TopoDS::Face(aShape1), aPnt1);
+        }
+      }
+      else if (aType2 == TopAbs_FACE)
+      {
+        if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+            aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaFF(TopoDS::Face(aShape1), TopoDS::Face(aShape2), aPnt1, aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaPF(aPnt1, TopoDS::Face(aShape2), aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
+        {
+          aValue = extremaPF(aPnt2, TopoDS::Face(aShape1), aPnt1);
+        }
+      }
+    }
+
+    if (aValue > 0.0)
+      aResult = aValue;
+  }
+  return aResult;
+}
+
 //==================================================================================================
 std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   const std::shared_ptr<GeomAPI_Shape> theCompound,
@@ -215,17 +676,17 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
 
   GeomShapePtr aResult = theCompound;
 
-  if(!theCompound.get()) {
+  if (!theCompound.get()) {
     return aResult;
   }
 
-  if(theType != GeomAPI_Shape::SHELL && theType != GeomAPI_Shape::COMPSOLID) {
+  if (theType != GeomAPI_Shape::SHELL && theType != GeomAPI_Shape::COMPSOLID) {
     return aResult;
   }
 
   TopAbs_ShapeEnum aTS = TopAbs_EDGE;
   TopAbs_ShapeEnum aTA = TopAbs_FACE;
-  if(theType == GeomAPI_Shape::COMPSOLID) {
+  if (theType == GeomAPI_Shape::COMPSOLID) {
     aTS = TopAbs_FACE;
     aTA = TopAbs_SOLID;
   }
@@ -238,15 +699,15 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   // Get free shapes.
   int anOrder = 0;
   const TopoDS_Shape& aShapesComp = theCompound->impl<TopoDS_Shape>();
-  for(TopoDS_Iterator anIter(aShapesComp); anIter.More(); anIter.Next(), anOrder++) {
+  for (TopoDS_Iterator anIter(aShapesComp); anIter.More(); anIter.Next(), anOrder++) {
     const TopoDS_Shape& aShape = anIter.Value();
-    if(aShape.ShapeType() > aTA) {
+    if (aShape.ShapeType() > aTA) {
       std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
       aGeomShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
       aResFreeShapes.push_back(aGeomShape);
       anInputOrder[aGeomShape] = anOrder;
     } else {
-      for(TopExp_Explorer anExp(aShape, aTA); anExp.More(); anExp.Next()) {
+      for (TopExp_Explorer anExp(aShape, aTA); anExp.More(); anExp.Next()) {
         anAncestorsOrder.Bind(anExp.Current(), anOrder);
       }
     }
@@ -255,7 +716,7 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   // Map sub-shapes and shapes.
   TopTools_IndexedDataMapOfShapeListOfShape aMapSA;
   TopExp::MapShapesAndAncestors(aShapesComp, aTS, aTA, aMapSA);
-  if(aMapSA.IsEmpty()) {
+  if (aMapSA.IsEmpty()) {
     return aResult;
   }
   theResuts.clear();
@@ -263,14 +724,13 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   // Get all shapes with common sub-shapes and free shapes.
   NCollection_Map<TopoDS_Shape> aFreeShapes;
   NCollection_Vector<NCollection_Map<TopoDS_Shape>> aShapesWithCommonSubshapes;
-  for(TopTools_IndexedDataMapOfShapeListOfShape::Iterator
+  for (TopTools_IndexedDataMapOfShapeListOfShape::Iterator
       anIter(aMapSA); anIter.More(); anIter.Next()) {
-    const TopoDS_Shape& aShape = anIter.Key();
     TopTools_ListOfShape& aListOfShape = anIter.ChangeValue();
-    if(aListOfShape.IsEmpty()) {
+    if (aListOfShape.IsEmpty()) {
       continue;
     }
-    else if(aListOfShape.Size() == 1) {
+    else if (aListOfShape.Size() == 1) {
       const TopoDS_Shape& aF = aListOfShape.First();
       aFreeShapes.Add(aF);
       aListOfShape.Clear();
@@ -283,17 +743,17 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
         aFreeShapes.Remove(aListIt.Value());
       }
       aListOfShape.Clear();
-      for(NCollection_List<TopoDS_Shape>::Iterator
+      for (NCollection_List<TopoDS_Shape>::Iterator
           aTempIter(aTempList); aTempIter.More(); aTempIter.Next()) {
         const TopoDS_Shape& aTempShape = aTempIter.Value();
-        for(TopTools_IndexedDataMapOfShapeListOfShape::Iterator
-            anIter(aMapSA); anIter.More(); anIter.Next()) {
-          TopTools_ListOfShape& aTempListOfShape = anIter.ChangeValue();
-          if(aTempListOfShape.IsEmpty()) {
+        for (TopTools_IndexedDataMapOfShapeListOfShape::Iterator
+            anIter2(aMapSA); anIter2.More(); anIter2.Next()) {
+          TopTools_ListOfShape& aTempListOfShape = anIter2.ChangeValue();
+          if (aTempListOfShape.IsEmpty()) {
             continue;
-          } else if(aTempListOfShape.Size() == 1 && aTempListOfShape.First() == aTempShape) {
+          } else if (aTempListOfShape.Size() == 1 && aTempListOfShape.First() == aTempShape) {
             aTempListOfShape.Clear();
-          } else if(aTempListOfShape.Size() > 1) {
+          } else if (aTempListOfShape.Size() > 1) {
             TopTools_ListOfShape::Iterator anIt1(aTempListOfShape);
             for (; anIt1.More(); anIt1.Next()) {
               if (anIt1.Value() == aTempShape) {
@@ -319,7 +779,7 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   }
 
   // Combine shapes with common sub-shapes.
-  for(NCollection_Vector<NCollection_Map<TopoDS_Shape>>::Iterator
+  for (NCollection_Vector<NCollection_Map<TopoDS_Shape>>::Iterator
       anIter(aShapesWithCommonSubshapes); anIter.More(); anIter.Next()) {
     TopoDS_Shell aShell;
     TopoDS_CompSolid aCSolid;
@@ -328,9 +788,9 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
     theType ==
       GeomAPI_Shape::COMPSOLID ? aBuilder.MakeCompSolid(aCSolid) : aBuilder.MakeShell(aShell);
     NCollection_Map<TopoDS_Shape>& aShapesMap = anIter.ChangeValue();
-    for(TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
+    for (TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
       const TopoDS_Shape& aShape = anExp.Current();
-      if(aShapesMap.Contains(aShape)) {
+      if (aShapesMap.Contains(aShape)) {
         theType ==
           GeomAPI_Shape::COMPSOLID ? aBuilder.Add(aCSolid, aShape) : aBuilder.Add(aShell, aShape);
         aShapesMap.Remove(aShape);
@@ -348,9 +808,9 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   }
 
   // Adding free shapes.
-  for(TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
+  for (TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
     const TopoDS_Shape& aShape = anExp.Current();
-    if(aFreeShapes.Contains(aShape)) {
+    if (aFreeShapes.Contains(aShape)) {
       std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
       aGeomShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
       aResFreeShapes.push_back(aGeomShape);
@@ -358,10 +818,10 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
     }
   }
 
-  if(aResCombinedShapes.size() == 1 && aResFreeShapes.size() == 0) {
+  if (aResCombinedShapes.size() == 1 && aResFreeShapes.size() == 0) {
     aResult = aResCombinedShapes.front();
     theResuts.push_back(aResult);
-  } else if(aResCombinedShapes.size() == 0 && aResFreeShapes.size() == 1) {
+  } else if (aResCombinedShapes.size() == 0 && aResFreeShapes.size() == 1) {
     aResult = aResFreeShapes.front();
     theResuts.push_back(aResult);
   } else {
@@ -371,10 +831,10 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
     // put to result compound and result list in accordance to the order numbers
     std::map<GeomShapePtr, int>::iterator anInputIter = anInputOrder.begin();
     std::map<int, GeomShapePtr> aNums;
-    for(; anInputIter != anInputOrder.end(); anInputIter++)
+    for (; anInputIter != anInputOrder.end(); anInputIter++)
       aNums[anInputIter->second] = anInputIter->first;
     std::map<int, GeomShapePtr>::iterator aNumsIter = aNums.begin();
-    for(; aNumsIter != aNums.end(); aNumsIter++) {
+    for (; aNumsIter != aNums.end(); aNumsIter++) {
       aBuilder.Add(aResultComp, (aNumsIter->second)->impl<TopoDS_Shape>());
       theResuts.push_back(aNumsIter->second);
     }
@@ -388,12 +848,12 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
 static void addSimpleShapeToList(const TopoDS_Shape& theShape,
                                  NCollection_List<TopoDS_Shape>& theList)
 {
-  if(theShape.IsNull()) {
+  if (theShape.IsNull()) {
     return;
   }
 
-  if(theShape.ShapeType() == TopAbs_COMPOUND) {
-    for(TopoDS_Iterator anIt(theShape); anIt.More(); anIt.Next()) {
+  if (theShape.ShapeType() == TopAbs_COMPOUND) {
+    for (TopoDS_Iterator anIt(theShape); anIt.More(); anIt.Next()) {
       addSimpleShapeToList(anIt.Value(), theList);
     }
   } else {
@@ -409,7 +869,7 @@ static TopoDS_Compound makeCompound(const NCollection_List<TopoDS_Shape> theShap
   BRep_Builder aBuilder;
   aBuilder.MakeCompound(aCompound);
 
-  for(NCollection_List<TopoDS_Shape>::Iterator anIt(theShapes); anIt.More(); anIt.Next()) {
+  for (NCollection_List<TopoDS_Shape>::Iterator anIt(theShapes); anIt.More(); anIt.Next()) {
     aBuilder.Add(aCompound, anIt.Value());
   }
 
@@ -520,7 +980,7 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::groupSharedTopology(
   for (NCollection_Vector<TopTools_MapOfShape>::Iterator anIt(aGroups); anIt.More(); anIt.Next()) {
     const TopTools_MapOfShape& aGroup = anIt.ChangeValue();
     GeomShapePtr aGeomShape(new GeomAPI_Shape());
-    if(aGroup.Size() == 1) {
+    if (aGroup.Size() == 1) {
       TopTools_MapOfShape::Iterator aOneShapeIter(aGroup);
       aGeomShape->setImpl(new TopoDS_Shape(aOneShapeIter.Value()));
     } else {
@@ -539,7 +999,7 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::groupSharedTopology(
     aBuilder.Add(aCompound, aGeomShape->impl<TopoDS_Shape>());
   }
 
-  if(!aCompound.IsNull()) {
+  if (!aCompound.IsNull()) {
     aResult->setImpl(new TopoDS_Shape(aCompound));
   }
 
@@ -578,7 +1038,7 @@ std::list<std::shared_ptr<GeomAPI_Pnt> >
     BRepBndLib::Add(aShape, aBndBox);
   }
 
-  if(theEnlarge != 0.0) {
+  if (theEnlarge != 0.0) {
     // We enlarge bounding box just to be sure that plane will be large enough to cut all objects.
     aBndBox.Enlarge(theEnlarge);
   }
@@ -587,10 +1047,9 @@ std::list<std::shared_ptr<GeomAPI_Pnt> >
   Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
   Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
   std::list<std::shared_ptr<GeomAPI_Pnt> > aResultPoints;
-  int aNum = 0;
-  for(int i = 0; i < 2; i++) {
-    for(int j = 0; j < 2; j++) {
-      for(int k = 0; k < 2; k++) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      for (int k = 0; k < 2; k++) {
         std::shared_ptr<GeomAPI_Pnt> aPnt(new GeomAPI_Pnt(aXArr[i], aYArr[j], aZArr[k]));
         aResultPoints.push_back(aPnt);
       }
@@ -607,27 +1066,27 @@ std::shared_ptr<GeomAPI_Face> GeomAlgoAPI_ShapeTools::fitPlaneToBox(
 {
   std::shared_ptr<GeomAPI_Face> aResultFace;
 
-  if(!thePlane.get()) {
+  if (!thePlane.get()) {
     return aResultFace;
   }
 
   const TopoDS_Shape& aShape = thePlane->impl<TopoDS_Shape>();
-  if(aShape.ShapeType() != TopAbs_FACE) {
+  if (aShape.ShapeType() != TopAbs_FACE) {
     return aResultFace;
   }
 
   TopoDS_Face aFace = TopoDS::Face(aShape);
   Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
-  if(aSurf.IsNull()) {
+  if (aSurf.IsNull()) {
     return aResultFace;
   }
 
   GeomLib_IsPlanarSurface isPlanar(aSurf);
-  if(!isPlanar.IsPlanar()) {
+  if (!isPlanar.IsPlanar()) {
     return aResultFace;
   }
 
-  if(thePoints.size() != 8) {
+  if (thePoints.size() != 8) {
     return aResultFace;
   }
 
@@ -644,10 +1103,10 @@ std::shared_ptr<GeomAPI_Face> GeomAlgoAPI_ShapeTools::fitPlaneToBox(
     const gp_Pnt& aPntOnFace = anIntAna.Point(1);
     Standard_Real aPntU(0), aPntV(0);
     GeomLib_Tool::Parameters(aFacePlane, aPntOnFace, Precision::Confusion(), aPntU, aPntV);
-    if(aPntU < UMin) UMin = aPntU;
-    if(aPntU > UMax) UMax = aPntU;
-    if(aPntV < VMin) VMin = aPntV;
-    if(aPntV > VMax) VMax = aPntV;
+    if (aPntU < UMin) UMin = aPntU;
+    if (aPntU > UMax) UMax = aPntU;
+    if (aPntV < VMin) VMin = aPntV;
+    if (aPntV > VMax) VMax = aPntV;
   }
   aResultFace.reset(new GeomAPI_Face());
   aResultFace->setImpl(new TopoDS_Face(BRepLib_MakeFace(aFacePln, UMin, UMax, VMin, VMax).Face()));
@@ -694,7 +1153,7 @@ void GeomAlgoAPI_ShapeTools::makeFacesWithHoles(const std::shared_ptr<GeomAPI_Pn
 
   BRepAlgo_FaceRestrictor aFRestrictor;
   aFRestrictor.Init(aFace, Standard_False, Standard_True);
-  for(ListOfShape::const_iterator anIt = theWires.cbegin();
+  for (ListOfShape::const_iterator anIt = theWires.cbegin();
       anIt != theWires.cend();
       ++anIt) {
     TopoDS_Wire aWire = TopoDS::Wire((*anIt)->impl<TopoDS_Shape>());
@@ -703,11 +1162,11 @@ void GeomAlgoAPI_ShapeTools::makeFacesWithHoles(const std::shared_ptr<GeomAPI_Pn
 
   aFRestrictor.Perform();
 
-  if(!aFRestrictor.IsDone()) {
+  if (!aFRestrictor.IsDone()) {
     return;
   }
 
-  for(; aFRestrictor.More(); aFRestrictor.Next()) {
+  for (; aFRestrictor.More(); aFRestrictor.Next()) {
     GeomShapePtr aShape(new GeomAPI_Shape());
     aShape->setImpl(new TopoDS_Shape(aFRestrictor.Current()));
     theFaces.push_back(aShape);
@@ -721,12 +1180,12 @@ std::shared_ptr<GeomAPI_Pln> GeomAlgoAPI_ShapeTools::findPlane(const ListOfShape
   BRep_Builder aBuilder;
   aBuilder.MakeCompound(aCompound);
 
-  for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
+  for (ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
     aBuilder.Add(aCompound, (*anIt)->impl<TopoDS_Shape>());
   }
   BRepBuilderAPI_FindPlane aFindPlane(aCompound);
 
-  if(aFindPlane.Found() != Standard_True) {
+  if (aFindPlane.Found() != Standard_True) {
     return std::shared_ptr<GeomAPI_Pln>();
   }
 
@@ -747,28 +1206,28 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(
   const std::shared_ptr<GeomAPI_Shape> theSubShape,
   const std::shared_ptr<GeomAPI_Shape> theBaseShape)
 {
-  if(!theSubShape.get() || !theBaseShape.get()) {
+  if (!theSubShape.get() || !theBaseShape.get()) {
     return false;
   }
 
   const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
 
-  if(aSubShape.ShapeType() == TopAbs_VERTEX) {
+  if (aSubShape.ShapeType() == TopAbs_VERTEX) {
     // If sub-shape is a vertex check distance to shape. If it is <= Precision::Confusion() then OK.
     BRepExtrema_DistShapeShape aDist(aBaseShape, aSubShape);
     aDist.Perform();
-    if(!aDist.IsDone() || aDist.Value() > Precision::Confusion()) {
+    if (!aDist.IsDone() || aDist.Value() > Precision::Confusion()) {
       return false;
     }
   } else if (aSubShape.ShapeType() == TopAbs_EDGE) {
-    if(aBaseShape.ShapeType() == TopAbs_FACE) {
+    if (aBaseShape.ShapeType() == TopAbs_FACE) {
       // Check that edge is on face surface.
       TopoDS_Face aFace = TopoDS::Face(aBaseShape);
       TopoDS_Edge anEdge = TopoDS::Edge(aSubShape);
       BRepLib_CheckCurveOnSurface aCheck(anEdge, aFace);
       aCheck.Perform();
-      if(!aCheck.IsDone() || aCheck.MaxDistance() > Precision::Confusion()) {
+      if (!aCheck.IsDone() || aCheck.MaxDistance() > Precision::Confusion()) {
         return false;
       }
 
@@ -777,15 +1236,15 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(
       ShapeAnalysis::FindBounds(anEdge, aV1, aV2);
       gp_Pnt aPnt1 = BRep_Tool::Pnt(aV1);
       gp_Pnt aPnt2 = BRep_Tool::Pnt(aV2);
-      for(TopExp_Explorer anExp(aBaseShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
+      for (TopExp_Explorer anExp(aBaseShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
         const TopoDS_Shape& anEdgeOnFace = anExp.Current();
         BRepExtrema_DistShapeShape aDist(anEdgeOnFace, anEdge);
         aDist.Perform();
-        if(aDist.IsDone() && aDist.Value() <= Precision::Confusion()) {
+        if (aDist.IsDone() && aDist.Value() <= Precision::Confusion()) {
           // Edge intersect face bound. Check that it is not on edge begin or end.
-          for(Standard_Integer anIndex = 1; anIndex <= aDist.NbSolution(); ++anIndex) {
+          for (Standard_Integer anIndex = 1; anIndex <= aDist.NbSolution(); ++anIndex) {
             gp_Pnt aPntOnSubShape = aDist.PointOnShape2(anIndex);
-            if(aPntOnSubShape.Distance(aPnt1) > Precision::Confusion()
+            if (aPntOnSubShape.Distance(aPnt1) > Precision::Confusion()
                 && aPntOnSubShape.Distance(aPnt2) > Precision::Confusion()) {
               return false;
             }
@@ -802,7 +1261,7 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(
       ShapeAnalysis_Surface aSAS(aSurface);
       gp_Pnt2d aPointOnFace = aSAS.ValueOfUV(aPointToCheck, Precision::Confusion());
       BRepTopAdaptor_FClass2d aFClass2d(aFace, Precision::Confusion());
-      if(aFClass2d.Perform(aPointOnFace) == TopAbs_OUT) {
+      if (aFClass2d.Perform(aPointOnFace) == TopAbs_OUT) {
         return false;
       }
 
@@ -819,7 +1278,7 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(
 //==================================================================================================
 bool GeomAlgoAPI_ShapeTools::isShapeValid(const std::shared_ptr<GeomAPI_Shape> theShape)
 {
-  if(!theShape.get()) {
+  if (!theShape.get()) {
     return false;
   }
 
@@ -833,7 +1292,7 @@ std::shared_ptr<GeomAPI_Shape>
 {
   GeomShapePtr anOuterWire;
 
-  if(!theFace.get() || !theFace->isFace()) {
+  if (!theFace.get() || !theFace->isFace()) {
     return anOuterWire;
   }
 
@@ -846,11 +1305,49 @@ std::shared_ptr<GeomAPI_Shape>
   return anOuterWire;
 }
 
+//==================================================================================================
+static bool boundaryOfEdge(const std::shared_ptr<GeomAPI_Edge> theEdge,
+                          const std::shared_ptr<GeomAPI_Vertex> theVertex,
+                          double& theParam)
+{
+  GeomPointPtr aPoint = theVertex->point();
+  GeomPointPtr aFirstPnt = theEdge->firstPoint();
+  double aFirstPntTol = theEdge->firstPointTolerance();
+  GeomPointPtr aLastPnt = theEdge->lastPoint();
+  double aLastPntTol = theEdge->lastPointTolerance();
+
+  double aFirst, aLast;
+  theEdge->getRange(aFirst, aLast);
+
+  bool isFirst = aPoint->distance(aFirstPnt) <= aFirstPntTol;
+  bool isLast = aPoint->distance(aLastPnt) <= aLastPntTol;
+  if (isFirst)
+    theParam = aFirst;
+  else if (isLast)
+    theParam = aLast;
+
+  return isFirst != isLast;
+}
+
+bool GeomAlgoAPI_ShapeTools::isTangent(const std::shared_ptr<GeomAPI_Edge> theEdge1,
+                                       const std::shared_ptr<GeomAPI_Edge> theEdge2,
+                                       const std::shared_ptr<GeomAPI_Vertex> theTgPoint)
+{
+  double aParE1 = 0, aParE2 = 0;
+  if (!boundaryOfEdge(theEdge1, theTgPoint, aParE1) ||
+      !boundaryOfEdge(theEdge2, theTgPoint, aParE2))
+    return false;
+
+  BRepAdaptor_Curve aC1(theEdge1->impl<TopoDS_Edge>());
+  BRepAdaptor_Curve aC2(theEdge2->impl<TopoDS_Edge>());
+  return BRepLProp::Continuity(aC1, aC2, aParE1, aParE2) >= GeomAbs_G1;
+}
+
 //==================================================================================================
 bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr<GeomAPI_Edge> theEdge,
                                         const std::shared_ptr<GeomAPI_Face> theFace)
 {
-  if(!theEdge.get() || !theFace.get()) {
+  if (!theEdge.get() || !theFace.get()) {
     return false;
   }
 
@@ -863,11 +1360,10 @@ bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr<GeomAPI_Edge> theE
 
 //==================================================================================================
 std::list<std::shared_ptr<GeomAPI_Vertex> > GeomAlgoAPI_ShapeTools::intersect(
-  const std::shared_ptr<GeomAPI_Edge> theEdge, const std::shared_ptr<GeomAPI_Face> theFace,
-  const bool thePointsOutsideFace)
+  const std::shared_ptr<GeomAPI_Edge> theEdge, const std::shared_ptr<GeomAPI_Face> theFace)
 {
   std::list<std::shared_ptr<GeomAPI_Vertex> > aResult;
-  if(!theEdge.get() || !theFace.get()) {
+  if (!theEdge.get() || !theFace.get()) {
     return aResult;
   }
 
@@ -882,7 +1378,7 @@ std::list<std::shared_ptr<GeomAPI_Vertex> > GeomAlgoAPI_ShapeTools::intersect(
   if (!anIntAlgo.IsDone())
     return aResult;
   // searching for points-intersection
-  for(int anIntNum = 1; anIntNum <= anIntAlgo.NbPoints() + anIntAlgo.NbSegments(); anIntNum++) {
+  for (int anIntNum = 1; anIntNum <= anIntAlgo.NbPoints() + anIntAlgo.NbSegments(); anIntNum++) {
     gp_Pnt anInt;
     if (anIntNum <= anIntAlgo.NbPoints()) {
       anInt = anIntAlgo.Point(anIntNum);
@@ -1046,7 +1542,7 @@ static TopoDS_Wire fixParametricGaps(const TopoDS_Wire& theWire)
 {
   TopoDS_Wire aFixedWire;
   Handle(Geom_Curve) aPrevCurve;
-  double aPrevLastParam = 0.0;
+  double aPrevLastParam = -Precision::Infinite();
 
   BRep_Builder aBuilder;
   aBuilder.MakeWire(aFixedWire);
@@ -1056,7 +1552,7 @@ static TopoDS_Wire fixParametricGaps(const TopoDS_Wire& theWire)
     TopoDS_Edge anEdge = aWExp.Current();
     double aFirst, aLast;
     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
-    if (aCurve == aPrevCurve) {
+    if (aCurve == aPrevCurve && Abs(aFirst - aPrevLastParam) > Precision::Confusion()) {
       // if parametric gap occurs, create new edge based on the copied curve
       aCurve = Handle(Geom_Curve)::DownCast(aCurve->Copy());
       TopoDS_Vertex aV1, aV2;
@@ -1076,24 +1572,67 @@ static TopoDS_Wire fixParametricGaps(const TopoDS_Wire& theWire)
   return aFixedWire;
 }
 
+//==================================================================================================
 std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_ShapeTools::wireToEdge(
       const std::shared_ptr<GeomAPI_Wire>& theWire)
 {
   GeomEdgePtr anEdge;
   if (theWire) {
     TopoDS_Wire aWire = theWire->impl<TopoDS_Wire>();
-    // Workaround: when concatenate a wire consisting of two edges based on the same B-spline curve
-    // (non-periodic, but having equal start and end points), first of which is placed at the end
-    // on the curve and second is placed at the start, this workaround copies second curve to avoid
-    // treating these edges as a single curve by setting trim parameters.
-    aWire = fixParametricGaps(aWire);
-    TopoDS_Edge aNewEdge = BRepAlgo::ConcatenateWireC0(aWire);
+    BRepTools_WireExplorer aWExp(aWire);
+    TopoDS_Edge aNewEdge = aWExp.Current();
+    aWExp.Next();
+    if (aWExp.More()) {
+      // Workaround for the closed wire to avoid jumping of its start point:
+      // split this wire for two parts, convert them to edges, then compose together
+      if (BRep_Tool::IsClosed(aWire)) {
+        aWire = TopoDS::Wire(BRepBuilderAPI_Copy(aWire).Shape());
+        aWExp.Init(aWire);
+        aNewEdge = aWExp.Current();
+
+        BRep_Builder().Remove(aWire, aNewEdge);
+        GeomWirePtr aSplitWire(new GeomAPI_Wire);
+        aSplitWire->setImpl(new TopoDS_Wire(aWire));
+        GeomEdgePtr aMergedEdge = wireToEdge(aSplitWire);
+
+        aWire = BRepBuilderAPI_MakeWire(aNewEdge, aMergedEdge->impl<TopoDS_Edge>());
+      }
+
+      // Workaround: when concatenate a wire consisting of two edges based on the same B-spline
+      // curve (non-periodic, but having equal start and end points), first of which is placed
+      // at the end on the curve and second is placed at the start, this workaround copies
+      // second curve to avoid treating these edges as a single curve by setting trim parameters.
+      aWire = fixParametricGaps(aWire);
+      aWire = BRepAlgo::ConcatenateWire(aWire, GeomAbs_G1); // join smooth parts of wire
+      aNewEdge = BRepAlgo::ConcatenateWireC0(aWire); // join C0 parts of wire
+
+      // Reapproximate the result edge to have the parameter equal to curvilinear abscissa.
+      static const int THE_MAX_DEGREE = 14;
+      static const int THE_MAX_INTERVALS = 32;
+      double aFirst, aLast;
+      Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aNewEdge, aFirst, aLast);
+#if OCC_VERSION_LARGE < 0x07070000
+      Handle(GeomAdaptor_HCurve) aHCurve = new GeomAdaptor_HCurve(aCurve);
+#else
+      Handle(GeomAdaptor_Curve) aHCurve = new GeomAdaptor_Curve(aCurve);
+#endif
+      Approx_CurvilinearParameter anApprox(aHCurve, Precision::Confusion(), aCurve->Continuity(),
+                                           THE_MAX_DEGREE, THE_MAX_INTERVALS);
+      if (anApprox.HasResult()) {
+        Handle(Geom_BSplineCurve) aNewCurve = anApprox.Curve3d();
+        TColStd_Array1OfReal aKnots = aNewCurve->Knots();
+        BSplCLib::Reparametrize(aFirst, aLast, aKnots);
+        aNewCurve->SetKnots(aKnots);
+        BRep_Builder().UpdateEdge(aNewEdge, aNewCurve, BRep_Tool::Tolerance(aNewEdge));
+      }
+    }
     anEdge = GeomEdgePtr(new GeomAPI_Edge);
     anEdge->setImpl(new TopoDS_Edge(aNewEdge));
   }
   return anEdge;
 }
 
+//==================================================================================================
 ListOfShape GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(const GeomShapePtr& theShape)
 {
   ListOfShape aSubShapes;
@@ -1114,4 +1653,148 @@ ListOfShape GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(const GeomShapePtr& the
   }
 
   return aSubShapes;
-}
\ No newline at end of file
+}
+
+//==================================================================================================
+static void getMinMaxPointsOnLine(const std::list<std::shared_ptr<GeomAPI_Pnt> >& thePoints,
+                                  const gp_Dir theDir,
+                                  double& theMin, double& theMax)
+{
+  theMin = RealLast();
+  theMax = RealFirst();
+  // Project bounding points on theDir
+  for (std::list<std::shared_ptr<GeomAPI_Pnt> >::const_iterator
+         aPointsIt = thePoints.begin(); aPointsIt != thePoints.end(); aPointsIt++) {
+    const gp_Pnt& aPnt = (*aPointsIt)->impl<gp_Pnt>();
+    gp_Dir aPntDir (aPnt.XYZ());
+    Standard_Real proj = (theDir*aPntDir) * aPnt.XYZ().Modulus();
+    if (proj < theMin) theMin = proj;
+    if (proj > theMax) theMax = proj;
+  }
+}
+
+//==================================================================================================
+void GeomAlgoAPI_ShapeTools::computeThroughAll(const ListOfShape& theObjects,
+                                               const ListOfShape& theBaseShapes,
+                                               const std::shared_ptr<GeomAPI_Dir> theDir,
+                                               double& theToSize, double& theFromSize)
+{
+  // Bounding box of objects
+  std::list<std::shared_ptr<GeomAPI_Pnt> > aBndObjs =
+      GeomAlgoAPI_ShapeTools::getBoundingBox(theObjects);
+  if (aBndObjs.size() != 8) {
+    return;
+  }
+
+  // the value to enlarge the bounding box of each object to make the extruded shape
+  // a little bit larger than overall objects to get the correct result of Boolean CUT operation
+  double anEnlargement = 0.1 * aBndObjs.front()->distance(aBndObjs.back());
+
+  // Prism direction
+  if (theDir.get()) {
+    // One direction for all prisms
+    gp_Dir aDir = theDir->impl<gp_Dir>();
+
+    // Bounding box of the base
+    std::list<std::shared_ptr<GeomAPI_Pnt> > aBndBases =
+        GeomAlgoAPI_ShapeTools::getBoundingBox(theBaseShapes);
+    if (aBndBases.size() != 8) {
+      return;
+    }
+
+    // Objects bounds
+    Standard_Real lowBnd, upperBnd;
+    getMinMaxPointsOnLine(aBndObjs, aDir, lowBnd, upperBnd);
+
+    // Base bounds
+    Standard_Real lowBase, upperBase;
+    getMinMaxPointsOnLine(aBndBases, aDir, lowBase, upperBase);
+
+    // ----------.-----.---------.--------------.-----------> theDir
+    //       lowBnd   lowBase   upperBase    upperBnd
+
+    theToSize = upperBnd - lowBase;
+    theFromSize = upperBase - lowBnd;
+  } else {
+    // Direction is a normal to each base shape (different normals to bases)
+    // So we calculate own sizes for each base shape
+    theToSize = 0.0;
+    theFromSize = 0.0;
+
+    for (ListOfShape::const_iterator anIt = theBaseShapes.begin();
+         anIt != theBaseShapes.end(); ++anIt) {
+      const GeomShapePtr& aBaseShape_i = (*anIt);
+      ListOfShape aBaseShapes_i;
+      aBaseShapes_i.push_back(aBaseShape_i);
+
+      // Bounding box of the base
+      std::list<std::shared_ptr<GeomAPI_Pnt> > aBndBases =
+          GeomAlgoAPI_ShapeTools::getBoundingBox(aBaseShapes_i, anEnlargement);
+      if (aBndBases.size() != 8) {
+        return;
+      }
+
+      // Direction (normal to aBaseShapes_i)
+      // Code like in GeomAlgoAPI_Prism
+      gp_Dir aDir;
+      const TopoDS_Shape& aBaseShape = aBaseShape_i->impl<TopoDS_Shape>();
+      BRepBuilderAPI_FindPlane aFindPlane(aBaseShape);
+      if (aFindPlane.Found() == Standard_True) {
+        Handle(Geom_Plane) aPlane;
+        if (aBaseShape.ShapeType() == TopAbs_FACE || aBaseShape.ShapeType() == TopAbs_SHELL) {
+          TopExp_Explorer anExp(aBaseShape, TopAbs_FACE);
+          const TopoDS_Shape& aFace = anExp.Current();
+          Handle(Geom_Surface) aSurface = BRep_Tool::Surface(TopoDS::Face(aFace));
+          if (aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
+            Handle(Geom_RectangularTrimmedSurface) aTrimSurface =
+              Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
+            aSurface = aTrimSurface->BasisSurface();
+          }
+          if (aSurface->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
+            return;
+          }
+          aPlane = Handle(Geom_Plane)::DownCast(aSurface);
+        } else {
+          aPlane = aFindPlane.Plane();
+        }
+        aDir = aPlane->Axis().Direction();
+      } else {
+        return;
+      }
+
+      // Objects bounds
+      Standard_Real lowBnd, upperBnd;
+      getMinMaxPointsOnLine(aBndObjs, aDir, lowBnd, upperBnd);
+
+      // Base bounds
+      Standard_Real lowBase, upperBase;
+      getMinMaxPointsOnLine(aBndBases, aDir, lowBase, upperBase);
+
+      // ----------.-----.---------.--------------.-----------> theDir
+      //       lowBnd   lowBase   upperBase    upperBnd
+
+      double aToSize_i = upperBnd - lowBase;
+      double aFromSize_i = upperBase - lowBnd;
+
+      if (aToSize_i > theToSize) theToSize = aToSize_i;
+      if (aFromSize_i > theFromSize) theFromSize = aFromSize_i;
+    }
+  }
+}
+
+ListOfShape GeomAlgoAPI_ShapeTools::getSharedFaces(const GeomShapePtr& theShape)
+{
+  ListOfShape aSharedFaces;
+  TopTools_IndexedDataMapOfShapeListOfShape aMapFS;
+  TopExp::MapShapesAndUniqueAncestors(theShape->impl<TopoDS_Shape>(),
+                                      TopAbs_FACE, TopAbs_SOLID, aMapFS);
+  for (Standard_Integer i = 1; i <= aMapFS.Extent(); i++) {
+    const TopTools_ListOfShape& ancestors = aMapFS.FindFromIndex(i);
+    if (ancestors.Size() > 1) {
+      GeomShapePtr aFace(new GeomAPI_Shape);
+      aFace->setImpl<TopoDS_Shape>(new TopoDS_Shape(aMapFS.FindKey(i)));
+      aSharedFaces.push_back(aFace);
+    }
+  }
+  return aSharedFaces;
+}