Salome HOME
Copyright update 2022
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_ShapeTools.cpp
index a47c77c7f28d1fa298a72a1613b71a5eabdd06ff..f95671f3e3d86de02f51c216e47705aa305abecc 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2022  CEA/DEN, EDF R&D
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 //
 // You should have received a copy of the GNU Lesser General Public
 // License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-// See http://www.salome-platform.org/ or
-// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 #include "GeomAlgoAPI_ShapeTools.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 <BRepTools_WireExplorer.hxx>
 #include <BRepTopAdaptor_FClass2d.hxx>
 #include <BRepClass_FaceClassifier.hxx>
+#include <BRepLib_CheckCurveOnSurface.hxx>
+#include <BRepLProp.hxx>
+
+#include <BOPAlgo_Builder.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>
+
+#include <GeomAdaptor_HCurve.hxx>
+
 #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>
 
 //==================================================================================================
 static GProp_GProps props(const TopoDS_Shape& theShape)
@@ -112,33 +132,50 @@ static GProp_GProps props(const TopoDS_Shape& theShape)
 }
 
 //==================================================================================================
-double GeomAlgoAPI_ShapeTools::volume(const std::shared_ptr<GeomAPI_Shape> theShape)
+double GeomAlgoAPI_ShapeTools::length(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()) {
+    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()) {
     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;
-  if (aShape.ShapeType() <= TopAbs_SOLID)
-    BRepGProp::VolumeProperties(aShape, aGProps, anEps);
-  else
-    BRepGProp::SurfaceProperties(aShape, aGProps, anEps);
-  return aGProps.Mass();
+  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 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;
@@ -147,20 +184,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);
@@ -185,14 +321,37 @@ 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;
+};
+}
+
+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();
 }
 
@@ -200,58 +359,69 @@ double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1,
 std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   const std::shared_ptr<GeomAPI_Shape> theCompound,
   const GeomAPI_Shape::ShapeType theType,
-  ListOfShape& theCombinedShapes,
-  ListOfShape& theFreeShapes)
+  ListOfShape& theResuts)
 {
+
+  ListOfShape aResCombinedShapes;
+  ListOfShape aResFreeShapes;
+
   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;
   }
 
-  theCombinedShapes.clear();
-  theFreeShapes.clear();
+  // map from the resulting shapes to minimal index of the used shape from theCompound list
+  std::map<GeomShapePtr, int> anInputOrder;
+  // map from ancestors-shapes to the index of shapes in theCompound
+  NCollection_DataMap<TopoDS_Shape, int> anAncestorsOrder;
 
   // Get free shapes.
+  int anOrder = 0;
   const TopoDS_Shape& aShapesComp = theCompound->impl<TopoDS_Shape>();
-  for(TopoDS_Iterator anIter(aShapesComp); anIter.More(); anIter.Next() ) {
+  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));
-      theFreeShapes.push_back(aGeomShape);
+      aResFreeShapes.push_back(aGeomShape);
+      anInputOrder[aGeomShape] = anOrder;
+    } else {
+      for (TopExp_Explorer anExp(aShape, aTA); anExp.More(); anExp.Next()) {
+        anAncestorsOrder.Bind(anExp.Current(), anOrder);
+      }
     }
   }
 
-  // Map subshapes and shapes.
+  // Map sub-shapes and shapes.
   TopTools_IndexedDataMapOfShapeListOfShape aMapSA;
   TopExp::MapShapesAndAncestors(aShapesComp, aTS, aTA, aMapSA);
-  if(aMapSA.IsEmpty()) {
+  if (aMapSA.IsEmpty()) {
     return aResult;
   }
+  theResuts.clear();
 
-  // Get all shapes with common subshapes and free shapes.
+  // 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();
@@ -264,17 +434,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) {
@@ -299,55 +469,65 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
     }
   }
 
-  // Combine shapes with common subshapes.
-  for(NCollection_Vector<NCollection_Map<TopoDS_Shape>>::Iterator
+  // Combine shapes with common sub-shapes.
+  for (NCollection_Vector<NCollection_Map<TopoDS_Shape>>::Iterator
       anIter(aShapesWithCommonSubshapes); anIter.More(); anIter.Next()) {
     TopoDS_Shell aShell;
     TopoDS_CompSolid aCSolid;
     TopoDS_Builder aBuilder;
+    anOrder = -1;
     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);
+        int aThisOrder = anAncestorsOrder.Find(aShape);
+        if (anOrder == -1 || aThisOrder < anOrder)
+          anOrder = aThisOrder; // take the minimum order position
       }
     }
     std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
     TopoDS_Shape* aSh = theType == GeomAPI_Shape::COMPSOLID ? new TopoDS_Shape(aCSolid) :
                                                               new TopoDS_Shape(aShell);
     aGeomShape->setImpl<TopoDS_Shape>(aSh);
-    theCombinedShapes.push_back(aGeomShape);
+    aResCombinedShapes.push_back(aGeomShape);
+    anInputOrder[aGeomShape] = anOrder;
   }
 
   // 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));
-      theFreeShapes.push_back(aGeomShape);
+      aResFreeShapes.push_back(aGeomShape);
+      anInputOrder[aGeomShape] = anAncestorsOrder.Find(aShape);
     }
   }
 
-  if(theCombinedShapes.size() == 1 && theFreeShapes.size() == 0) {
-    aResult = theCombinedShapes.front();
-  } else if(theCombinedShapes.size() == 0 && theFreeShapes.size() == 1) {
-    aResult = theFreeShapes.front();
+  if (aResCombinedShapes.size() == 1 && aResFreeShapes.size() == 0) {
+    aResult = aResCombinedShapes.front();
+    theResuts.push_back(aResult);
+  } else if (aResCombinedShapes.size() == 0 && aResFreeShapes.size() == 1) {
+    aResult = aResFreeShapes.front();
+    theResuts.push_back(aResult);
   } else {
     TopoDS_Compound aResultComp;
     TopoDS_Builder aBuilder;
     aBuilder.MakeCompound(aResultComp);
-    for(ListOfShape::const_iterator anIter = theCombinedShapes.cbegin();
-        anIter != theCombinedShapes.cend(); anIter++) {
-      aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
-    }
-    for(ListOfShape::const_iterator anIter = theFreeShapes.cbegin();
-        anIter != theFreeShapes.cend(); anIter++) {
-      aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
+    // 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++)
+      aNums[anInputIter->second] = anInputIter->first;
+    std::map<int, GeomShapePtr>::iterator aNumsIter = aNums.begin();
+    for (; aNumsIter != aNums.end(); aNumsIter++) {
+      aBuilder.Add(aResultComp, (aNumsIter->second)->impl<TopoDS_Shape>());
+      theResuts.push_back(aNumsIter->second);
     }
     aResult->setImpl(new TopoDS_Shape(aResultComp));
   }
@@ -359,12 +539,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 {
@@ -380,7 +560,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());
   }
 
@@ -444,7 +624,7 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::groupSharedTopology(
         aKeysIt.Next()) {
         const TopTools_ListOfShape& anOtherConnected = aVertexShapesMap(aKeysIt.Value());
         if (!anOtherConnected.Contains(aConnected)) {
-          // Other connected group does not containt shape from our connected group
+          // Other connected group does not contain shape from our connected group
           continue;
         }
         // Other is connected to our, so add them to our connected
@@ -487,11 +667,11 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::groupSharedTopology(
   TopoDS_Compound aCompound;
   BRep_Builder aBuilder;
   aBuilder.MakeCompound(aCompound);
-  ListOfShape aCompSolids, aFreeSolids;
+  ListOfShape aSolids;
   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 {
@@ -505,19 +685,36 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::groupSharedTopology(
       aGeomShape->setImpl(new TopoDS_Shape(makeCompound(anOrderedGoup)));
       aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
                                                          GeomAPI_Shape::COMPSOLID,
-                                                         aCompSolids,
-                                                         aFreeSolids);
+                                                         aSolids);
     }
     aBuilder.Add(aCompound, aGeomShape->impl<TopoDS_Shape>());
   }
 
-  if(!aCompound.IsNull()) {
+  if (!aCompound.IsNull()) {
     aResult->setImpl(new TopoDS_Shape(aCompound));
   }
 
   return aResult;
 }
 
+//==================================================================================================
+bool GeomAlgoAPI_ShapeTools::hasSharedTopology(const ListOfShape& theShapes,
+                                               const GeomAPI_Shape::ShapeType theShapeType)
+{
+  TopTools_IndexedMapOfShape aSubs;
+  for (ListOfShape::const_iterator anIt = theShapes.begin(); anIt != theShapes.end(); ++anIt) {
+    TopTools_IndexedMapOfShape aCurSubs;
+    TopExp::MapShapes((*anIt)->impl<TopoDS_Shape>(), (TopAbs_ShapeEnum)theShapeType, aCurSubs);
+    for (TopTools_IndexedMapOfShape::Iterator aSubIt(aCurSubs); aSubIt.More(); aSubIt.Next()) {
+      if (aSubs.Contains(aSubIt.Value()))
+        return true;
+      else
+        aSubs.Add(aSubIt.Value());
+    }
+  }
+  return false;
+}
+
 //==================================================================================================
 std::list<std::shared_ptr<GeomAPI_Pnt> >
   GeomAlgoAPI_ShapeTools::getBoundingBox(const ListOfShape& theShapes, const double theEnlarge)
@@ -532,7 +729,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);
   }
@@ -541,10 +738,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);
       }
@@ -554,29 +750,6 @@ std::list<std::shared_ptr<GeomAPI_Pnt> >
   return aResultPoints;
 }
 
-//==================================================================================================
-std::shared_ptr<GeomAPI_Shape>
-  GeomAlgoAPI_ShapeTools::faceToInfinitePlane(const std::shared_ptr<GeomAPI_Shape> theFace)
-{
-  if (!theFace.get())
-    return std::shared_ptr<GeomAPI_Shape>();
-
-  TopoDS_Face aPlaneFace = TopoDS::Face(theFace->impl<TopoDS_Shape>());
-  if (aPlaneFace.IsNull())
-    return std::shared_ptr<GeomAPI_Shape>();
-
-  Handle(Geom_Plane) aPlane = Handle(Geom_Plane)::DownCast(BRep_Tool::Surface(aPlaneFace));
-  if (aPlane.IsNull())
-    return std::shared_ptr<GeomAPI_Shape>();
-
-  // make an infinity face on the plane
-  TopoDS_Shape anInfiniteFace = BRepBuilderAPI_MakeFace(aPlane->Pln()).Shape();
-
-  std::shared_ptr<GeomAPI_Shape> aResult(new GeomAPI_Shape);
-  aResult->setImpl(new TopoDS_Shape(anInfiniteFace));
-  return aResult;
-}
-
 //==================================================================================================
 std::shared_ptr<GeomAPI_Face> GeomAlgoAPI_ShapeTools::fitPlaneToBox(
   const std::shared_ptr<GeomAPI_Shape> thePlane,
@@ -584,27 +757,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;
   }
 
@@ -621,10 +794,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()));
@@ -637,23 +810,26 @@ void GeomAlgoAPI_ShapeTools::findBounds(const std::shared_ptr<GeomAPI_Shape> the
                                         std::shared_ptr<GeomAPI_Vertex>& theV1,
                                         std::shared_ptr<GeomAPI_Vertex>& theV2)
 {
-  if(!theShape.get()) {
-    std::shared_ptr<GeomAPI_Vertex> aVertex(new GeomAPI_Vertex);
+  static GeomVertexPtr aVertex;
+  if (!aVertex) {
+    aVertex = GeomVertexPtr(new GeomAPI_Vertex);
     aVertex->setImpl(new TopoDS_Vertex());
-    theV1 = aVertex;
-    theV2 = aVertex;
-    return;
   }
 
-  const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
-  TopoDS_Vertex aV1, aV2;
-  ShapeAnalysis::FindBounds(aShape, aV1, aV2);
-
-  std::shared_ptr<GeomAPI_Vertex> aGeomV1(new GeomAPI_Vertex()), aGeomV2(new GeomAPI_Vertex());
-  aGeomV1->setImpl(new TopoDS_Vertex(aV1));
-  aGeomV2->setImpl(new TopoDS_Vertex(aV2));
-  theV1 = aGeomV1;
-  theV2 = aGeomV2;
+  theV1 = aVertex;
+  theV2 = aVertex;
+
+  if (theShape) {
+    const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
+    TopoDS_Vertex aV1, aV2;
+    ShapeAnalysis::FindBounds(aShape, aV1, aV2);
+
+    std::shared_ptr<GeomAPI_Vertex> aGeomV1(new GeomAPI_Vertex()), aGeomV2(new GeomAPI_Vertex());
+    aGeomV1->setImpl(new TopoDS_Vertex(aV1));
+    aGeomV2->setImpl(new TopoDS_Vertex(aV2));
+    theV1 = aGeomV1;
+    theV2 = aGeomV2;
+  }
 }
 
 //==================================================================================================
@@ -668,7 +844,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>());
@@ -677,11 +853,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);
@@ -695,12 +871,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>();
   }
 
@@ -721,28 +897,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;
       }
 
@@ -751,15 +927,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;
             }
@@ -776,7 +952,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;
       }
 
@@ -793,7 +969,7 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(
 //==================================================================================================
 bool GeomAlgoAPI_ShapeTools::isShapeValid(const std::shared_ptr<GeomAPI_Shape> theShape)
 {
-  if(!theShape.get()) {
+  if (!theShape.get()) {
     return false;
   }
 
@@ -807,7 +983,7 @@ std::shared_ptr<GeomAPI_Shape>
 {
   GeomShapePtr anOuterWire;
 
-  if(!theFace.get() || !theFace->isFace()) {
+  if (!theFace.get() || !theFace->isFace()) {
     return anOuterWire;
   }
 
@@ -820,11 +996,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;
   }
 
@@ -837,11 +1051,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;
   }
 
@@ -856,7 +1069,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);
@@ -997,6 +1210,7 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::findShape(
 }
 
 //==================================================================================================
+#ifdef FEATURE_MULTIROTATION_TWO_DIRECTIONS
 std::shared_ptr<GeomAPI_Dir> GeomAlgoAPI_ShapeTools::buildDirFromAxisAndShape(
                                     const std::shared_ptr<GeomAPI_Shape> theBaseShape,
                                     const std::shared_ptr<GeomAPI_Ax1> theAxis)
@@ -1012,13 +1226,14 @@ std::shared_ptr<GeomAPI_Dir> GeomAlgoAPI_ShapeTools::buildDirFromAxisAndShape(
                                                     aCentreOfMassPoint.Z()-aPoint.Z()));
   return aDir;
 }
+#endif
 
 //==================================================================================================
 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);
@@ -1028,7 +1243,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;
@@ -1048,24 +1263,63 @@ 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);
+      Handle(GeomAdaptor_HCurve) aHCurve = new GeomAdaptor_HCurve(aCurve);
+      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;
@@ -1086,4 +1340,131 @@ 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;
+    }
+  }
+}