Salome HOME
updated copyright message
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IHealingOperations.cxx
index 08e0c37579c4a127c7079e9e442890761f7cf948..240113ec931c7768b0eb1a29faed09ceb9c47556 100644 (file)
@@ -1,47 +1,66 @@
-#ifdef WNT
+// Copyright (C) 2007-2023  CEA, EDF, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// 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
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifdef WIN32
 #pragma warning( disable:4786 )
 #endif
 
-#include <Standard_Stream.hxx>
+#include <Standard_Version.hxx>
 
 #include <GEOMImpl_IHealingOperations.hxx>
-
 #include <GEOM_PythonDump.hxx>
-
 #include <GEOMImpl_HealingDriver.hxx>
 #include <GEOMImpl_Types.hxx>
 #include <GEOMImpl_IHealing.hxx>
+#include <GEOMImpl_IVector.hxx>
+#include <GEOMImpl_VectorDriver.hxx>
 #include <GEOMImpl_CopyDriver.hxx>
-
+#include <ShHealOper_ModifStats.hxx>
 #include <ShHealOper_ShapeProcess.hxx>
 
-#include "utilities.h"
-#include <OpUtil.hxx>
+#include <utilities.h>
 #include <Utils_ExceptHandlers.hxx>
 
+#include <BRep_Builder.hxx>
 #include <ShapeAnalysis_FreeBounds.hxx>
-
-#include <TopoDS_Compound.hxx>
-#include <TopExp_Explorer.hxx>
-
 #include <TColStd_HArray1OfExtendedString.hxx>
 #include <TColStd_HSequenceOfTransient.hxx>
 #include <TCollection_AsciiString.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopTools_SequenceOfShape.hxx>
+#include <TopoDS_Compound.hxx>
 
-#include <TDF_Tool.hxx>
-
+#include <Standard_Failure.hxx>
 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
 
-
 //=============================================================================
 /*!
  *   constructor:
  */
 //=============================================================================
-
-GEOMImpl_IHealingOperations::GEOMImpl_IHealingOperations (GEOM_Engine* theEngine, int theDocID)
-: GEOM_IOperations(theEngine, theDocID)
+GEOMImpl_IHealingOperations::GEOMImpl_IHealingOperations (GEOM_Engine* theEngine)
+: GEOM_IOperations(theEngine)
 {
+  myModifStats = new ShHealOper_ModifStats;
   MESSAGE("GEOMImpl_IHealingOperations::GEOMImpl_IHealingOperations");
 }
 
@@ -50,9 +69,9 @@ GEOMImpl_IHealingOperations::GEOMImpl_IHealingOperations (GEOM_Engine* theEngine
  *  destructor
  */
 //=============================================================================
-
 GEOMImpl_IHealingOperations::~GEOMImpl_IHealingOperations()
 {
+  delete myModifStats;
   MESSAGE("GEOMImpl_IHealingOperations::~GEOMImpl_IHealingOperations");
 }
 
@@ -95,7 +114,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::ShapeProcess (Handle(GEOM_Objec
   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
 
   // Add a new object
-  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GEOM_COPY );
 
   //Add the function
   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), SHAPE_PROCESS);
@@ -113,20 +132,20 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::ShapeProcess (Handle(GEOM_Objec
     HI.SetParameters( theParams );
     HI.SetValues( theValues );
   }
+  HI.SetStatistics( myModifStats );
 
   //Compute the translation
-  try
-  {
+  try {
+    OCC_CATCH_SIGNALS;
     if (!GetSolver()->ComputeFunction(aFunction))
     {
       SetErrorCode("Shape Healing algorithm failed");
       return NULL;
     }
   }
-  catch (Standard_Failure)
+  catch (Standard_Failure& aFail)
   {
-    Handle(Standard_Failure) aFail = Standard_Failure::Caught();
-    SetErrorCode(aFail->GetMessageString());
+    SetErrorCode(aFail.GetMessageString());
     return NULL;
   }
 
@@ -165,9 +184,9 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::ShapeProcess (Handle(GEOM_Objec
  *  ShapeProcess
  */
 //=============================================================================
-void GEOMImpl_IHealingOperations::GetShapeProcessParameters (list<string>& theOperations,
-                                                             list<string>& theParams,
-                                                             list<string>& theValues)
+void GEOMImpl_IHealingOperations::GetShapeProcessParameters (std::list<std::string>& theOperations,
+                                                             std::list<std::string>& theParams,
+                                                             std::list<std::string>& theValues)
 {
   ShHealOper_ShapeProcess aHealer;
   TColStd_SequenceOfAsciiString anOperators;
@@ -176,9 +195,9 @@ void GEOMImpl_IHealingOperations::GetShapeProcessParameters (list<string>& theOp
   {
     for ( Standard_Integer i = 1; i <= anOperators.Length(); i++ )
     {
-      string anOperation = anOperators.Value( i ).ToCString();
+      std::string anOperation = anOperators.Value( i ).ToCString();
       if ( GetOperatorParameters( anOperation, theParams, theValues ) )
-       theOperations.push_back( anOperation );
+        theOperations.push_back( anOperation );
       else
         nbOperatorErrors++;
     }
@@ -200,23 +219,23 @@ void GEOMImpl_IHealingOperations::GetShapeProcessParameters (list<string>& theOp
  *  GetOperatorParameters
  */
 //=============================================================================
-bool GEOMImpl_IHealingOperations::GetOperatorParameters( const string theOperation, 
-                                                        list<string>& theParams,
-                                                        list<string>& theValues )
+bool GEOMImpl_IHealingOperations::GetOperatorParameters( const std::string &     theOperation,
+                                                         std::list<std::string>& theParams,
+                                                         std::list<std::string>& theValues )
 {
   ShHealOper_ShapeProcess aHealer;
   int nbParamValueErrors( 0 );
-  list<string> aParams;
+  std::list<std::string> aParams;
   if ( GetParameters( theOperation, aParams ) ) {
-    for ( list<string>::iterator it = aParams.begin(); it != aParams.end(); ++it ) {
+    for ( std::list<std::string>::iterator it = aParams.begin(); it != aParams.end(); ++it ) {
       TCollection_AsciiString aParam( (Standard_CString)(*it).c_str() );
       TCollection_AsciiString aValue;
       if ( aHealer.GetParameter( aParam, aValue ) ) {
-       theParams.push_back( aParam.ToCString() );
-       theValues.push_back( aValue.ToCString() );
+        theParams.push_back( aParam.ToCString() );
+        theValues.push_back( aValue.ToCString() );
       }
       else
-       nbParamValueErrors++;
+        nbParamValueErrors++;
     }
   }
   else
@@ -236,8 +255,8 @@ bool GEOMImpl_IHealingOperations::GetOperatorParameters( const string theOperati
  *  GetParameters
  */
 //=============================================================================
-bool GEOMImpl_IHealingOperations::GetParameters (const string theOperation,
-                                                 list<string>& theParams)
+bool GEOMImpl_IHealingOperations::GetParameters (const std::string theOperation,
+                                                 std::list<std::string>& theParams)
 {
   if ( theOperation == "SplitAngle" ) {
     theParams.push_back( "SplitAngle.Angle" );
@@ -252,6 +271,11 @@ bool GEOMImpl_IHealingOperations::GetParameters (const string theOperation,
   } else if( theOperation == "DropSmallEdges" ) {
     theParams.push_back( "DropSmallEdges.Tolerance3d" );
 
+  } else if( theOperation == "DropSmallSolids" ) {
+    theParams.push_back( "DropSmallSolids.WidthFactorThreshold" );
+    theParams.push_back( "DropSmallSolids.VolumeThreshold" );
+    theParams.push_back( "DropSmallSolids.MergeSolids" );
+
   } else if( theOperation == "BSplineRestriction" ) {
     theParams.push_back( "BSplineRestriction.SurfaceMode" );
     theParams.push_back( "BSplineRestriction.Curve3dMode" );
@@ -299,41 +323,41 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::SuppressFaces
   // set error code, check parameters
   SetErrorCode(KO);
 
-  if ( theObject.IsNull() ) // if theFaces.IsNull() - it's OK, it means that ALL faces must be removed..
+  if (theObject.IsNull()) // if theFaces.IsNull() - it's OK, it means that ALL faces must be removed..
     return NULL;
 
   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
-  if(aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
+  if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
 
   // Add a new object
-  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject(GEOM_COPY);
 
   //Add the function
   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), SUPPRESS_FACES);
 
-  if(aFunction.IsNull()) return NULL;
+  if (aFunction.IsNull()) return NULL;
 
   //Check if the function is set correctly
-  if(aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
+  if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
 
   // prepare "data container" class IHealing
-  GEOMImpl_IHealing HI(aFunction);
-  HI.SetFaces( theFaces );
-  HI.SetOriginal( aLastFunction );
+  GEOMImpl_IHealing HI (aFunction);
+  HI.SetFaces(theFaces);
+  HI.SetOriginal(aLastFunction);
+  HI.SetStatistics( myModifStats );
 
   //Compute the translation
-  try
-  {
+  try {
+    OCC_CATCH_SIGNALS;
     if (!GetSolver()->ComputeFunction(aFunction))
     {
       SetErrorCode("Healing driver failed");
       return NULL;
     }
   }
-  catch (Standard_Failure)
+  catch (Standard_Failure& aFail)
   {
-       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
-    SetErrorCode(aFail->GetMessageString());
+    SetErrorCode(aFail.GetMessageString());
     return NULL;
   }
 
@@ -350,7 +374,6 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::SuppressFaces
   return aNewObject;
 }
 
-
 //=============================================================================
 /*!
  *  CloseContour
@@ -374,7 +397,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::CloseContour
   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
 
   // Add a new object
-  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GEOM_COPY );
 
   //Add the function
   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), CLOSE_CONTOUR);
@@ -389,20 +412,20 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::CloseContour
   HI.SetWires( theWires );
   HI.SetIsCommonVertex( isCommonVertex );
   HI.SetOriginal( aLastFunction );
+  HI.SetStatistics( myModifStats );
 
   //Compute the translation
-  try
-  {
+  try {
+    OCC_CATCH_SIGNALS;
     if (!GetSolver()->ComputeFunction(aFunction))
     {
       SetErrorCode("Healing driver failed");
       return NULL;
     }
   }
-  catch (Standard_Failure)
+  catch (Standard_Failure& aFail)
   {
-       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
-    SetErrorCode(aFail->GetMessageString());
+    SetErrorCode(aFail.GetMessageString());
     return NULL;
   }
 
@@ -442,7 +465,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::RemoveIntWires
   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
 
   // Add a new object
-  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GEOM_COPY );
 
   //Add the function
   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), REMOVE_INT_WIRES);
@@ -456,20 +479,20 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::RemoveIntWires
   GEOMImpl_IHealing HI(aFunction);
   HI.SetWires( theWires );
   HI.SetOriginal( aLastFunction );
+  HI.SetStatistics( myModifStats );
 
   //Compute the translation
-  try
-  {
+  try {
+    OCC_CATCH_SIGNALS;
     if (!GetSolver()->ComputeFunction(aFunction))
     {
       SetErrorCode("Healing driver failed");
       return NULL;
     }
   }
-  catch (Standard_Failure)
+  catch (Standard_Failure& aFail)
   {
-    Handle(Standard_Failure) aFail = Standard_Failure::Caught();
-    SetErrorCode(aFail->GetMessageString());
+    SetErrorCode(aFail.GetMessageString());
     return NULL;
   }
 
@@ -508,7 +531,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::FillHoles (Handle(GEOM_Object)
   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
 
   // Add a new object
-  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GEOM_COPY );
 
   //Add the function
   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), FILL_HOLES);
@@ -522,20 +545,20 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::FillHoles (Handle(GEOM_Object)
   GEOMImpl_IHealing HI(aFunction);
   HI.SetWires( theWires );
   HI.SetOriginal( aLastFunction );
+  HI.SetStatistics( myModifStats );
 
   //Compute the translation
-  try
-  {
+  try {
+    OCC_CATCH_SIGNALS;
     if (!GetSolver()->ComputeFunction(aFunction))
     {
       SetErrorCode("Healing driver failed");
       return NULL;
     }
   }
-  catch (Standard_Failure)
+  catch (Standard_Failure& aFail)
   {
-       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
-    SetErrorCode(aFail->GetMessageString());
+    SetErrorCode(aFail.GetMessageString());
     return NULL;
   }
 
@@ -561,24 +584,31 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::FillHoles (Handle(GEOM_Object)
  *  Sew
  */
 //=============================================================================
-Handle(GEOM_Object) GEOMImpl_IHealingOperations::Sew (Handle(GEOM_Object) theObject,
-                                                      double theTolerance)
+Handle(GEOM_Object)
+GEOMImpl_IHealingOperations::Sew (std::list<Handle(GEOM_Object)>& theObjects,
+                                  double                          theTolerance,
+                                  bool                            isAllowNonManifold)
 {
   // set error code, check parameters
   SetErrorCode(KO);
 
-  if (theObject.IsNull())
+  if (theObjects.empty())
     return NULL;
 
-  Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
-  if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
+  Handle(TColStd_HSequenceOfTransient) objects =
+    GEOM_Object::GetLastFunctions( theObjects );
+  if ( objects.IsNull() || objects->IsEmpty() ) {
+    SetErrorCode("NULL argument shape");
+    return NULL;
+  }
 
   // Add a new object
-  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GEOM_COPY );
 
   //Add the function
-  aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), SEWING);
-
+  int aFunctionType = (isAllowNonManifold ? SEWING_NON_MANIFOLD : SEWING);
+  Handle(GEOM_Function) aFunction =
+    aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), aFunctionType);
   if (aFunction.IsNull()) return NULL;
 
   //Check if the function is set correctly
@@ -587,27 +617,92 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::Sew (Handle(GEOM_Object) theObj
   // prepare "data container" class IHealing
   GEOMImpl_IHealing HI(aFunction);
   HI.SetTolerance( theTolerance );
-  HI.SetOriginal( aLastFunction );
+  HI.SetOriginal( theObjects.front()->GetLastFunction() ); objects->Remove(1);
+  HI.SetShapes( objects );
+  HI.SetStatistics( myModifStats );
 
-  //Compute the translation
-  try
-  {
+  //Compute the result
+  try {
+    OCC_CATCH_SIGNALS;
     if (!GetSolver()->ComputeFunction(aFunction))
     {
       SetErrorCode("Healing driver failed");
       return NULL;
     }
   }
-  catch (Standard_Failure)
-  {
-       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
-    SetErrorCode(aFail->GetMessageString());
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
     return NULL;
   }
 
   //Make a Python command
-  GEOM::TPythonDump(aFunction) << aNewObject << " = geompy.Sew("
-                               << theObject << ", " << theTolerance << ")";
+  GEOM::TPythonDump pd(aFunction);
+  
+  pd << aNewObject << " = geompy.Sew(" << theObjects << ", " << theTolerance;
+
+  if (isAllowNonManifold) {
+    pd << ", True";
+  }
+
+  pd << ")";
+
+  SetErrorCode(OK);
+  return aNewObject;
+}
+
+//=============================================================================
+/*!
+ *  RemoveInternalFaces
+ */
+//=============================================================================
+Handle(GEOM_Object)
+GEOMImpl_IHealingOperations::RemoveInternalFaces (std::list< Handle(GEOM_Object)> & theSolids)
+{
+  // set error code, check parameters
+  SetErrorCode(KO);
+
+  if (theSolids.empty())
+    return NULL;
+
+  Handle(TColStd_HSequenceOfTransient) objects = GEOM_Object::GetLastFunctions( theSolids );
+  if ( objects.IsNull() || objects->IsEmpty() ) {
+    SetErrorCode("NULL argument shape");
+    return NULL;
+  }
+
+  // Add a new object
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject(GEOM_COPY);
+
+  //Add the function
+  Handle(GEOM_Function)
+    aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), REMOVE_INTERNAL_FACES);
+  if (aFunction.IsNull()) return NULL;
+
+  //Check if the function is set correctly
+  if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
+
+  // prepare "data container" class IHealing
+  GEOMImpl_IHealing HI (aFunction);
+  HI.SetOriginal( theSolids.front()->GetLastFunction() ); objects->Remove(1);
+  HI.SetShapes( objects );
+  HI.SetStatistics( myModifStats );
+
+  //Compute the result
+  try {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aFunction))
+    {
+      SetErrorCode("Healing driver failed");
+      return NULL;
+    }
+  }
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
+    return NULL;
+  }
+
+  //Make a Python command
+  GEOM::TPythonDump(aFunction) << aNewObject << " = geompy.RemoveInternalFaces(" << theSolids << ")";
 
   SetErrorCode(OK);
   return aNewObject;
@@ -633,7 +728,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::DivideEdge (Handle(GEOM_Object)
   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
 
   // Add a new object
-  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GEOM_COPY );
 
   //Add the function
   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), DIVIDE_EDGE);
@@ -649,20 +744,18 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::DivideEdge (Handle(GEOM_Object)
   HI.SetDevideEdgeValue( theValue );
   HI.SetIsByParameter( isByParameter );
   HI.SetOriginal( aLastFunction );
+  HI.SetStatistics( myModifStats );
 
   //Compute the translation
-  try
-  {
-    if (!GetSolver()->ComputeFunction(aFunction))
-    {
+  try {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aFunction)) {
       SetErrorCode("Healing driver failed");
       return NULL;
     }
   }
-  catch (Standard_Failure)
-  {
-       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
-    SetErrorCode(aFail->GetMessageString());
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
     return NULL;
   }
 
@@ -674,27 +767,190 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::DivideEdge (Handle(GEOM_Object)
   return aNewObject;
 }
 
+//=============================================================================
+/*!
+ *  DivideEdgeByPoint
+ */
+//=============================================================================
+Handle(GEOM_Object)
+GEOMImpl_IHealingOperations::DivideEdgeByPoint (Handle(GEOM_Object)               theObject,
+                                                int                               theIndex,
+                                                std::list< Handle(GEOM_Object)> & thePoints)
+{
+  // set error code, check parameters
+  SetErrorCode(KO);
+
+  if (theObject.IsNull() || thePoints.empty() )
+    return NULL;
+
+  Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
+  if (aLastFunction.IsNull() )
+    return NULL; //There is no function which creates an object to be processed
+
+  Handle(TColStd_HSequenceOfTransient) aPointFunc = GEOM_Object::GetLastFunctions( thePoints );
+  if ( aPointFunc.IsNull() || aPointFunc->IsEmpty() ) {
+    SetErrorCode("NULL argument points");
+    return NULL;
+  }
+
+  // Add a new object
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GEOM_COPY );
+
+  //Add the function
+  aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), DIVIDE_EDGE_BY_POINT);
+
+  if (aFunction.IsNull()) return NULL;
+
+  //Check if the function is set correctly
+  if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
+
+  // prepare "data container" class IHealing
+  GEOMImpl_IHealing HI(aFunction);
+  HI.SetIndex     ( theIndex );
+  HI.SetOriginal  ( aLastFunction );
+  HI.SetShapes    ( aPointFunc );
+
+  HI.SetStatistics( myModifStats );
+
+  //Compute the translation
+  try {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aFunction)) {
+      SetErrorCode("Healing driver failed");
+      return NULL;
+    }
+  }
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
+    return NULL;
+  }
+
+  //Make a Python command
+  GEOM::TPythonDump(aFunction)
+    << aNewObject << " = geompy.DivideEdgeByPoint(" << theObject
+    << ", " << theIndex << ", " << thePoints << ")";
+
+  SetErrorCode(OK);
+  return aNewObject;
+}
+
+//=============================================================================
+/*!
+ *  FuseCollinearEdgesWithinWire
+ */
+//=============================================================================
+Handle(GEOM_Object) GEOMImpl_IHealingOperations::FuseCollinearEdgesWithinWire
+                                   (Handle(GEOM_Object) theWire,
+                                    std::list<Handle(GEOM_Object)> theVertices)
+{
+  SetErrorCode(KO);
+
+  if (theWire.IsNull()) return NULL;
+
+  // Add a new object
+  Handle(GEOM_Object) aRes = GetEngine()->AddObject(theWire->GetType());
+
+  // Add a new function
+  Handle(GEOM_Function) aFunction;
+  aFunction = aRes->AddFunction(GEOMImpl_HealingDriver::GetID(), FUSE_COLLINEAR_EDGES);
+  if (aFunction.IsNull()) return NULL;
+
+  // Check if the function is set correctly
+  if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
+
+  GEOMImpl_IHealing aCI (aFunction);
+  aCI.SetStatistics( myModifStats );
+
+  Handle(GEOM_Function) aRefShape = theWire->GetLastFunction();
+  if (aRefShape.IsNull()) return NULL;
+  aCI.SetOriginal(aRefShape);
+
+  Handle(TColStd_HSequenceOfTransient) aVertices = new TColStd_HSequenceOfTransient;
+  std::list<Handle(GEOM_Object)>::iterator it = theVertices.begin();
+  for (; it != theVertices.end(); it++) {
+    Handle(GEOM_Function) aRefSh = (*it)->GetLastFunction();
+    if (aRefSh.IsNull()) {
+      SetErrorCode("NULL argument shape for the shape construction");
+      return NULL;
+    }
+    aVertices->Append(aRefSh);
+  }
+  aCI.SetShapes(aVertices);
+
+  // Compute the new wire
+  try {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aFunction)) {
+      SetErrorCode("Healing driver failed");
+      return NULL;
+    }
+  }
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
+    return NULL;
+  }
+
+  // Make a Python command
+  GEOM::TPythonDump pd (aFunction);
+  pd << aRes << " = geompy.FuseCollinearEdgesWithinWire(" << theWire << ", [";
+  // Vertices
+  it = theVertices.begin();
+  if (it != theVertices.end()) {
+    pd << (*it++);
+    while (it != theVertices.end()) {
+      pd << ", " << (*it++);
+    }
+  }
+  pd << "])";
+
+  SetErrorCode(OK);
+  return aRes;
+}
+
 //=============================================================================
 /*!
  *  GetFreeBoundary
  */
 //=============================================================================
-bool GEOMImpl_IHealingOperations::GetFreeBoundary (Handle(GEOM_Object) theObject,
-                                                  Handle(TColStd_HSequenceOfTransient)& theClosed,
-                                                  Handle(TColStd_HSequenceOfTransient)& theOpen )
+bool GEOMImpl_IHealingOperations::GetFreeBoundary (Handle(TColStd_HSequenceOfTransient)& theObjects,
+                                                   Handle(TColStd_HSequenceOfTransient)& theClosed,
+                                                   Handle(TColStd_HSequenceOfTransient)& theOpen )
 {
   // set error code, check parameters
   SetErrorCode(KO);
 
-  if ( theObject.IsNull() || theClosed.IsNull() || theOpen.IsNull() )
+  if ( theObjects.IsNull() || theObjects->Length() == 0 ||
+       theClosed.IsNull()  || theOpen.IsNull() )
     return false;
 
-  TopoDS_Shape aShape = theObject->GetValue();
-  if ( aShape.IsNull() )
-    return false;
+  TopoDS_Shape aShape;
+  TopTools_SequenceOfShape shapes;
+  for ( int ind = 1; ind <= theObjects->Length(); ind++)
+  {
+    Handle(GEOM_Object) aRefShape = Handle(GEOM_Object)::DownCast( theObjects->Value(ind));
+    if ( aRefShape.IsNull() )
+      return false;
+    aShape = aRefShape->GetValue();
+    if ( aShape.IsNull() )
+      return false;
+    shapes.Append( aShape );
+  }
+
+  if ( shapes.Length() > 1 )
+  {
+    TopoDS_Compound compound;
+    BRep_Builder builder;
+    builder.MakeCompound( compound );
+    for ( int i = 1; i <= shapes.Length(); ++i )
+      builder.Add( compound, shapes( i ) );
+
+    aShape = compound;
+  }
 
   // get free boundary shapes
-  ShapeAnalysis_FreeBounds anAnalizer( aShape );
+
+  ShapeAnalysis_FreeBounds anAnalizer(aShape, Standard_False,
+                                      Standard_True, Standard_True);
   TopoDS_Compound aClosed = anAnalizer.GetClosedWires();
   TopoDS_Compound anOpen = anAnalizer.GetOpenWires();
 
@@ -704,7 +960,7 @@ bool GEOMImpl_IHealingOperations::GetFreeBoundary (Handle(GEOM_Object) theObject
   TopExp_Explorer anExp;
   for ( anExp.Init( aClosed, TopAbs_WIRE ); anExp.More(); anExp.Next() )
   {
-    anObj = GetEngine()->AddObject( GetDocID(), GEOM_FREE_BOUNDS );
+    anObj = GetEngine()->AddObject( GEOM_FREE_BOUNDS );
     aFunction = anObj->AddFunction( GEOMImpl_CopyDriver::GetID(), COPY_WITHOUT_REF );
     TopoDS_Shape aValueShape = anExp.Current();
     aFunction->SetValue( aValueShape );
@@ -712,42 +968,247 @@ bool GEOMImpl_IHealingOperations::GetFreeBoundary (Handle(GEOM_Object) theObject
   }
   for ( anExp.Init( anOpen, TopAbs_WIRE ); anExp.More(); anExp.Next() )
   {
-    anObj = GetEngine()->AddObject( GetDocID(), GEOM_FREE_BOUNDS );
+    anObj = GetEngine()->AddObject( GEOM_FREE_BOUNDS );
     aFunction = anObj->AddFunction( GEOMImpl_CopyDriver::GetID(), COPY_WITHOUT_REF );
     TopoDS_Shape aValueShape = anExp.Current();
     aFunction->SetValue( aValueShape );
     theOpen->Append(anObj);
   }
 
+  if(!aFunction.IsNull()) {
+
+    //Make a Python command
+    GEOM::TPythonDump pd (aFunction);
+
+    Standard_Integer i, aLen = theClosed->Length();
+    if (aLen > 0) {
+      pd << "(isDone, [";
+      for (i = 1; i <= aLen; i++) {
+        Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theClosed->Value(i));
+        pd << anObj_i << ((i < aLen) ? ", " : "");
+      }
+      pd << "], ";
+    } else {
+      pd << "(isDone, empty_list, ";
+    }
+
+    aLen = theOpen->Length();
+    if (aLen > 0) {
+      pd << "[";
+      for (i = 1; i <= aLen; i++) {
+        Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theOpen->Value(i));
+        pd << anObj_i << ((i < aLen) ? ", " : "");
+      }
+      pd << "]";
+    } else {
+      pd << "empty_list";
+    }
+
+    pd << ") = geompy.GetFreeBoundary(" << theObjects << ")";
+  }
+
+  SetErrorCode(OK);
+  return true;
+}
+
+
+//=============================================================================
+/*!
+ *  ChangeOrientation
+ */
+//=============================================================================
+Handle(GEOM_Object) GEOMImpl_IHealingOperations::ChangeOrientation (Handle(GEOM_Object) theObject)
+{
+  // set error code, check parameters
+  SetErrorCode(KO);
+
+  if (theObject.IsNull())
+    return NULL;
+
+  if (!theObject->IsMainShape()) {
+    SetErrorCode("Sub-shape cannot be transformed - need to create a copy");
+    return NULL;
+  }
+
+  Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
+  if (aLastFunction.IsNull())
+    return NULL; //There is no function which creates an object to be processed
+
+  if (theObject->GetType() == GEOM_VECTOR) { // Mantis issue 21066
+    //Add the function
+    aFunction = theObject->AddFunction(GEOMImpl_VectorDriver::GetID(), VECTOR_REVERSE);
+
+    //Check if the function is set correctly
+    if (aFunction.IsNull()) return NULL;
+    if (aFunction->GetDriverGUID() != GEOMImpl_VectorDriver::GetID()) return NULL;
+
+    // prepare "data container" class IVector
+    GEOMImpl_IVector aVI (aFunction);
+    aVI.SetCurve(aLastFunction);
+
+    myModifStats->Clear();
+    myModifStats->AddModif( "Vector reversed" );
+  }
+  else {
+    //Add the function
+    aFunction = theObject->AddFunction(GEOMImpl_HealingDriver::GetID(), CHANGE_ORIENTATION);
+
+    //Check if the function is set correctly
+    if (aFunction.IsNull()) return NULL;
+    if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
+
+    // prepare "data container" class IHealing
+    GEOMImpl_IHealing HI (aFunction);
+    HI.SetOriginal(aLastFunction);
+    HI.SetStatistics( myModifStats );
+  }
+
+  //Compute the translation
+  try {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aFunction)) {
+      SetErrorCode("Healing driver failed");
+      return NULL;
+    }
+  }
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
+    return NULL;
+  }
+
   //Make a Python command
-  GEOM::TPythonDump pd (aFunction);
+  GEOM::TPythonDump(aFunction) << "geompy.ChangeOrientationShell("
+                               << theObject << ")";
+
+  SetErrorCode(OK);
+  return theObject;
+}
+
+//=============================================================================
+/*!
+ *  ChangeOrientationCopy
+ */
+//=============================================================================
+Handle(GEOM_Object) GEOMImpl_IHealingOperations::ChangeOrientationCopy (Handle(GEOM_Object) theObject)
+{
+  // set error code, check parameters
+  SetErrorCode(KO);
+
+  if (theObject.IsNull())
+    return NULL;
 
-  Standard_Integer i, aLen = theClosed->Length();
-  if (aLen > 0) {
-    pd << "(isDone, [";
-    for (i = 1; i <= aLen; i++) {
-      Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theClosed->Value(i));
-      pd << anObj_i << ((i < aLen) ? ", " : "");
+  Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
+  if (aLastFunction.IsNull())
+    return NULL; //There is no function which creates an object to be processed
+
+  // Add a new object
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject(GEOM_COPY);
+
+  if (theObject->GetType() == GEOM_VECTOR) { // Mantis issue 21066
+    //Add the function
+    aFunction = aNewObject->AddFunction(GEOMImpl_VectorDriver::GetID(), VECTOR_REVERSE);
+
+    //Check if the function is set correctly
+    if (aFunction.IsNull()) return NULL;
+    if (aFunction->GetDriverGUID() != GEOMImpl_VectorDriver::GetID()) return NULL;
+
+    // prepare "data container" class IVector
+    GEOMImpl_IVector aVI (aFunction);
+    aVI.SetCurve(aLastFunction);
+
+    myModifStats->Clear();
+    myModifStats->AddModif( "Vector reversed" );
+  }
+  else {
+    //Add the function
+    aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), CHANGE_ORIENTATION);
+
+    //Check if the function is set correctly
+    if (aFunction.IsNull()) return NULL;
+    if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
+
+    // prepare "data container" class IHealing
+    GEOMImpl_IHealing aHI (aFunction);
+    aHI.SetOriginal(aLastFunction);
+    aHI.SetStatistics( myModifStats );
+  }
+
+  // Compute the result
+  try {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aFunction)) {
+      SetErrorCode("Healing driver failed");
+      return NULL;
     }
-    pd << "], ";
-  } else {
-    pd << "(isDone, empty_list, ";
   }
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
+    return NULL;
+  }
+
+  //Make a Python command
+  GEOM::TPythonDump(aFunction) << aNewObject << " = geompy.ChangeOrientationShellCopy("
+                               << theObject << ")";
+
+  SetErrorCode(OK);
+  return aNewObject;
+}
+
+//=============================================================================
+/*!
+ *  LimitTolerance
+ */
+//=============================================================================
+Handle(GEOM_Object) GEOMImpl_IHealingOperations::LimitTolerance (Handle(GEOM_Object) theObject,
+                                                                 double theTolerance,
+                                                                 TopAbs_ShapeEnum theType)
+{
+  // Set error code, check parameters
+  SetErrorCode(KO);
 
-  aLen = theOpen->Length();
-  if (aLen > 0) {
-    pd << "[";
-    for (i = 1; i <= aLen; i++) {
-      Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theOpen->Value(i));
-      pd << anObj_i << ((i < aLen) ? ", " : "");
+  if (theObject.IsNull())
+    return NULL;
+
+  Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
+  if (aLastFunction.IsNull())
+    return NULL; // There is no function which creates an object to be processed
+
+  // Add a new object
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject(theObject->GetType());
+
+  // Add the function
+  aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), LIMIT_TOLERANCE);
+
+  if (aFunction.IsNull())
+    return NULL;
+
+  // Check if the function is set correctly
+  if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
+
+  // Prepare "data container" class IHealing
+  GEOMImpl_IHealing HI (aFunction);
+  HI.SetOriginal(aLastFunction);
+  HI.SetTolerance(theTolerance);
+  HI.SetType(theType);
+  HI.SetStatistics( myModifStats );
+
+  // Compute
+  try {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aFunction)) {
+      SetErrorCode("Healing driver failed");
+      return NULL;
     }
-    pd << "]";
-  } else {
-    pd << "empty_list";
+  }
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
+    return NULL;
   }
 
-  pd << ") = geompy.GetFreeBoundary(" << theObject << ")";
+  // Make a Python command
+  GEOM::TPythonDump(aFunction) << aNewObject << " = geompy.LimitTolerance("
+                               << theObject << ", " << theTolerance << ")";
 
   SetErrorCode(OK);
-  return true;
+  return aNewObject;
 }