Salome HOME
updated copyright message
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IHealingOperations.cxx
index 98f56bf19f4b88f89d3c6c86fa94d92015bbc646..240113ec931c7768b0eb1a29faed09ceb9c47556 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
+// 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
@@ -6,7 +6,7 @@
 // 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.
+// 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
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
-#ifdef WNT
+#ifdef WIN32
 #pragma warning( disable:4786 )
 #endif
 
 #include <Standard_Version.hxx>
-#include <Standard_Stream.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 <Basics_OCCTVersion.hxx>
-
-#include "utilities.h"
-#include <OpUtil.hxx>
+#include <utilities.h>
 #include <Utils_ExceptHandlers.hxx>
 
-#include <ShHealOper_ShapeProcess.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 <TDF_Tool.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopTools_SequenceOfShape.hxx>
+#include <TopoDS_Compound.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");
 }
 
@@ -78,6 +71,7 @@ GEOMImpl_IHealingOperations::GEOMImpl_IHealingOperations (GEOM_Engine* theEngine
 //=============================================================================
 GEOMImpl_IHealingOperations::~GEOMImpl_IHealingOperations()
 {
+  delete myModifStats;
   MESSAGE("GEOMImpl_IHealingOperations::~GEOMImpl_IHealingOperations");
 }
 
@@ -120,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);
@@ -138,22 +132,20 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::ShapeProcess (Handle(GEOM_Objec
     HI.SetParameters( theParams );
     HI.SetValues( theValues );
   }
+  HI.SetStatistics( myModifStats );
 
   //Compute the translation
   try {
-#if OCC_VERSION_LARGE > 0x06010000
     OCC_CATCH_SIGNALS;
-#endif
     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;
   }
 
@@ -227,7 +219,7 @@ void GEOMImpl_IHealingOperations::GetShapeProcessParameters (std::list<std::stri
  *  GetOperatorParameters
  */
 //=============================================================================
-bool GEOMImpl_IHealingOperations::GetOperatorParameters( const std::string theOperation,
+bool GEOMImpl_IHealingOperations::GetOperatorParameters( const std::string &     theOperation,
                                                          std::list<std::string>& theParams,
                                                          std::list<std::string>& theValues )
 {
@@ -279,6 +271,11 @@ bool GEOMImpl_IHealingOperations::GetParameters (const std::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" );
@@ -333,7 +330,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::SuppressFaces
   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);
@@ -347,22 +344,20 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::SuppressFaces
   GEOMImpl_IHealing HI (aFunction);
   HI.SetFaces(theFaces);
   HI.SetOriginal(aLastFunction);
+  HI.SetStatistics( myModifStats );
 
   //Compute the translation
   try {
-#if OCC_VERSION_LARGE > 0x06010000
     OCC_CATCH_SIGNALS;
-#endif
     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;
   }
 
@@ -402,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);
@@ -417,22 +412,20 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::CloseContour
   HI.SetWires( theWires );
   HI.SetIsCommonVertex( isCommonVertex );
   HI.SetOriginal( aLastFunction );
+  HI.SetStatistics( myModifStats );
 
   //Compute the translation
   try {
-#if OCC_VERSION_LARGE > 0x06010000
     OCC_CATCH_SIGNALS;
-#endif
     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;
   }
 
@@ -472,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);
@@ -486,22 +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 {
-#if OCC_VERSION_LARGE > 0x06010000
     OCC_CATCH_SIGNALS;
-#endif
     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;
   }
 
@@ -540,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);
@@ -554,22 +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 {
-#if OCC_VERSION_LARGE > 0x06010000
     OCC_CATCH_SIGNALS;
-#endif
     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;
   }
 
@@ -595,27 +584,31 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::FillHoles (Handle(GEOM_Object)
  *  Sew
  */
 //=============================================================================
-Handle(GEOM_Object) GEOMImpl_IHealingOperations::Sew (Handle(GEOM_Object) theObject,
-                                                      double theTolerance,
-                                                      bool isAllowNonManifold)
+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
   int aFunctionType = (isAllowNonManifold ? SEWING_NON_MANIFOLD : SEWING);
-
-  aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), aFunctionType);
-
+  Handle(GEOM_Function) aFunction =
+    aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), aFunctionType);
   if (aFunction.IsNull()) return NULL;
 
   //Check if the function is set correctly
@@ -624,33 +617,31 @@ 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
+  //Compute the result
   try {
-#if OCC_VERSION_LARGE > 0x06010000
     OCC_CATCH_SIGNALS;
-#endif
     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 pd(aFunction);
   
-  pd << aNewObject << " = geompy.Sew(" << theObject << ", " << theTolerance;
+  pd << aNewObject << " = geompy.Sew(" << theObjects << ", " << theTolerance;
 
   if (isAllowNonManifold) {
-    pd << ", true";
+    pd << ", True";
   }
 
   pd << ")";
@@ -659,6 +650,64 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::Sew (Handle(GEOM_Object) theObj
   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;
+}
+
 //=============================================================================
 /*!
  *  DivideEdge
@@ -679,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);
@@ -695,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 OCC_VERSION_LARGE > 0x06010000
     OCC_CATCH_SIGNALS;
-#endif
     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;
   }
 
@@ -720,6 +767,73 @@ 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
@@ -734,7 +848,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::FuseCollinearEdgesWithinWire
   if (theWire.IsNull()) return NULL;
 
   // Add a new object
-  Handle(GEOM_Object) aRes = GetEngine()->AddObject(GetDocID(), theWire->GetType());
+  Handle(GEOM_Object) aRes = GetEngine()->AddObject(theWire->GetType());
 
   // Add a new function
   Handle(GEOM_Function) aFunction;
@@ -745,6 +859,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::FuseCollinearEdgesWithinWire
   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;
@@ -764,17 +879,14 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::FuseCollinearEdgesWithinWire
 
   // Compute the new wire
   try {
-#if OCC_VERSION_LARGE > 0x06010000
     OCC_CATCH_SIGNALS;
-#endif
     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;
   }
 
@@ -800,28 +912,45 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::FuseCollinearEdgesWithinWire
  *  GetFreeBoundary
  */
 //=============================================================================
-bool GEOMImpl_IHealingOperations::GetFreeBoundary (Handle(GEOM_Object) theObject,
+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
 
-#if OCC_VERSION_LARGE > 0x06030008
   ShapeAnalysis_FreeBounds anAnalizer(aShape, Standard_False,
                                       Standard_True, Standard_True);
-#else
-  ShapeAnalysis_FreeBounds anAnalizer(aShape);
-#endif
   TopoDS_Compound aClosed = anAnalizer.GetClosedWires();
   TopoDS_Compound anOpen = anAnalizer.GetOpenWires();
 
@@ -831,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 );
@@ -839,7 +968,7 @@ 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 );
@@ -875,7 +1004,7 @@ bool GEOMImpl_IHealingOperations::GetFreeBoundary (Handle(GEOM_Object) theObject
       pd << "empty_list";
     }
 
-    pd << ") = geompy.GetFreeBoundary(" << theObject << ")";
+    pd << ") = geompy.GetFreeBoundary(" << theObjects << ")";
   }
 
   SetErrorCode(OK);
@@ -916,6 +1045,9 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::ChangeOrientation (Handle(GEOM_
     // prepare "data container" class IVector
     GEOMImpl_IVector aVI (aFunction);
     aVI.SetCurve(aLastFunction);
+
+    myModifStats->Clear();
+    myModifStats->AddModif( "Vector reversed" );
   }
   else {
     //Add the function
@@ -928,21 +1060,19 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::ChangeOrientation (Handle(GEOM_
     // prepare "data container" class IHealing
     GEOMImpl_IHealing HI (aFunction);
     HI.SetOriginal(aLastFunction);
+    HI.SetStatistics( myModifStats );
   }
 
   //Compute the translation
   try {
-#if OCC_VERSION_LARGE > 0x06010000
     OCC_CATCH_SIGNALS;
-#endif
     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;
   }
 
@@ -972,7 +1102,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::ChangeOrientationCopy (Handle(G
     return NULL; //There is no function which creates an object to be processed
 
   // Add a new object
-  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject(GetDocID(), theObject->GetType());
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject(GEOM_COPY);
 
   if (theObject->GetType() == GEOM_VECTOR) { // Mantis issue 21066
     //Add the function
@@ -985,6 +1115,9 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::ChangeOrientationCopy (Handle(G
     // prepare "data container" class IVector
     GEOMImpl_IVector aVI (aFunction);
     aVI.SetCurve(aLastFunction);
+
+    myModifStats->Clear();
+    myModifStats->AddModif( "Vector reversed" );
   }
   else {
     //Add the function
@@ -997,21 +1130,19 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::ChangeOrientationCopy (Handle(G
     // prepare "data container" class IHealing
     GEOMImpl_IHealing aHI (aFunction);
     aHI.SetOriginal(aLastFunction);
+    aHI.SetStatistics( myModifStats );
   }
 
   // Compute the result
   try {
-#if OCC_VERSION_LARGE > 0x06010000
     OCC_CATCH_SIGNALS;
-#endif
     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;
   }
 
@@ -1029,7 +1160,8 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::ChangeOrientationCopy (Handle(G
  */
 //=============================================================================
 Handle(GEOM_Object) GEOMImpl_IHealingOperations::LimitTolerance (Handle(GEOM_Object) theObject,
-                                                                 double theTolerance)
+                                                                 double theTolerance,
+                                                                 TopAbs_ShapeEnum theType)
 {
   // Set error code, check parameters
   SetErrorCode(KO);
@@ -1042,7 +1174,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::LimitTolerance (Handle(GEOM_Obj
     return NULL; // There is no function which creates an object to be processed
 
   // Add a new object
-  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject(GetDocID(), theObject->GetType());
+  Handle(GEOM_Object) aNewObject = GetEngine()->AddObject(theObject->GetType());
 
   // Add the function
   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), LIMIT_TOLERANCE);
@@ -1057,20 +1189,19 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::LimitTolerance (Handle(GEOM_Obj
   GEOMImpl_IHealing HI (aFunction);
   HI.SetOriginal(aLastFunction);
   HI.SetTolerance(theTolerance);
+  HI.SetType(theType);
+  HI.SetStatistics( myModifStats );
 
   // Compute
   try {
-#if OCC_VERSION_LARGE > 0x06010000
     OCC_CATCH_SIGNALS;
-#endif
     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;
   }