]> OCCT Git - occt.git/commitdiff
Shape Healing interface update #189
authordkulikov <dkulikov@opencascade.com>
Fri, 13 Dec 2024 17:42:09 +0000 (17:42 +0000)
committerdkulikov <dkulikov@opencascade.com>
Mon, 16 Dec 2024 13:46:46 +0000 (13:46 +0000)
New class XSAlgo_ShapeProcessor is added. It reimplements functionality
of XSAlgo_AlgoContainer and makes it more convenient to use.
XSAlgo_AlgoContainer is now internally uses methods of
XSAlgo_ShapeProcessor when possible.
New overload of Perform() method is added to class ShapeProcess. It
accepts a set of flags that defines required operations instead of
string.

src/DE/DE_ShapeFixParameters.hxx
src/ShapeProcess/ShapeProcess.cxx
src/ShapeProcess/ShapeProcess.hxx
src/XSAlgo/FILES
src/XSAlgo/XSAlgo_AlgoContainer.cxx
src/XSAlgo/XSAlgo_AlgoContainer.hxx
src/XSAlgo/XSAlgo_ShapeProcessor.cxx [new file with mode: 0644]
src/XSAlgo/XSAlgo_ShapeProcessor.hxx [new file with mode: 0644]

index eb975ce02d69642c5b7f4a5337f409f2760463d7..c02450aa9196eae24a04fda07196df61685c797e 100644 (file)
@@ -14,6 +14,8 @@
 #ifndef _DE_ShapeFixParameters_HeaderFile
 #define _DE_ShapeFixParameters_HeaderFile
 
+#include <TopAbs_ShapeEnum.hxx>
+
 //! Struct for shape healing parameters storage
 struct DE_ShapeFixParameters
 {
@@ -21,62 +23,64 @@ struct DE_ShapeFixParameters
   enum class FixMode : signed char
   {
     FixOrNot = -1, //!< Procedure will be executed or not (depending on the situation)
-    NotFix = 0,    //!< Procedure will be executed
-    Fix = 1        //!< Procedure will be executed anyway
+    NotFix   = 0,  //!< Procedure will be executed
+    Fix      = 1   //!< Procedure will be executed anyway
   };
 
-  double Tolerance3d = 1.e-6;
-  double MaxTolerance3d = 1.0;
-  double MinTolerance3d = 1.e-7;
-  FixMode FixFreeShellMode = FixMode::FixOrNot;
-  FixMode FixFreeFaceMode = FixMode::FixOrNot;
-  FixMode FixFreeWireMode = FixMode::FixOrNot;
-  FixMode FixSameParameterMode = FixMode::FixOrNot;
-  FixMode FixSolidMode = FixMode::FixOrNot;
-  FixMode FixShellOrientationMode = FixMode::FixOrNot;
-  FixMode CreateOpenSolidMode = FixMode::NotFix;
-  FixMode FixShellMode = FixMode::FixOrNot;
-  FixMode FixFaceOrientationMode = FixMode::FixOrNot;
-  FixMode FixFaceMode = FixMode::FixOrNot;
-  FixMode FixWireMode = FixMode::FixOrNot;
-  FixMode FixOrientationMode = FixMode::FixOrNot;
-  FixMode FixAddNaturalBoundMode = FixMode::FixOrNot;
-  FixMode FixMissingSeamMode = FixMode::FixOrNot;
-  FixMode FixSmallAreaWireMode = FixMode::FixOrNot;
-  FixMode RemoveSmallAreaFaceMode = FixMode::FixOrNot;
-  FixMode FixIntersectingWiresMode = FixMode::FixOrNot;
-  FixMode FixLoopWiresMode = FixMode::FixOrNot;
-  FixMode FixSplitFaceMode = FixMode::FixOrNot;
-  FixMode AutoCorrectPrecisionMode = FixMode::FixOrNot;
-  FixMode ModifyTopologyMode = FixMode::NotFix;
-  FixMode ModifyGeometryMode = FixMode::Fix;
-  FixMode ClosedWireMode = FixMode::Fix;
-  FixMode PreferencePCurveMode = FixMode::Fix;
-  FixMode FixReorderMode = FixMode::FixOrNot;
-  FixMode FixSmallMode = FixMode::FixOrNot;
-  FixMode FixConnectedMode = FixMode::FixOrNot;
-  FixMode FixEdgeCurvesMode = FixMode::FixOrNot;
-  FixMode FixDegeneratedMode = FixMode::FixOrNot;
-  FixMode FixLackingMode = FixMode::FixOrNot;
-  FixMode FixSelfIntersectionMode = FixMode::FixOrNot;
-  FixMode RemoveLoopMode = FixMode::FixOrNot;
-  FixMode FixReversed2dMode = FixMode::FixOrNot;
-  FixMode FixRemovePCurveMode = FixMode::FixOrNot;
-  FixMode FixRemoveCurve3dMode = FixMode::FixOrNot;
-  FixMode FixAddPCurveMode = FixMode::FixOrNot;
-  FixMode FixAddCurve3dMode = FixMode::FixOrNot;
-  FixMode FixSeamMode = FixMode::FixOrNot;
-  FixMode FixShiftedMode = FixMode::FixOrNot;
-  FixMode FixEdgeSameParameterMode = FixMode::NotFix;
-  FixMode FixNotchedEdgesMode = FixMode::FixOrNot;
-  FixMode FixTailMode = FixMode::NotFix;
-  FixMode MaxTailAngle = FixMode::NotFix;
-  FixMode MaxTailWidth = FixMode::FixOrNot;
-  FixMode FixSelfIntersectingEdgeMode = FixMode::FixOrNot;
-  FixMode FixIntersectingEdgesMode = FixMode::FixOrNot;
-  FixMode FixNonAdjacentIntersectingEdgesMode = FixMode::FixOrNot;
-  FixMode FixVertexPositionMode = FixMode::NotFix;
-  FixMode FixVertexToleranceMode = FixMode::FixOrNot;
+  double           Tolerance3d                         = 1.e-6;
+  double           MaxTolerance3d                      = 1.0;
+  double           MinTolerance3d                      = 1.e-7;
+  TopAbs_ShapeEnum DetalizationLevel                   = TopAbs_ShapeEnum::TopAbs_FACE;
+  bool             NonManifold                         = false;
+  FixMode          FixFreeShellMode                    = FixMode::FixOrNot;
+  FixMode          FixFreeFaceMode                     = FixMode::FixOrNot;
+  FixMode          FixFreeWireMode                     = FixMode::FixOrNot;
+  FixMode          FixSameParameterMode                = FixMode::FixOrNot;
+  FixMode          FixSolidMode                        = FixMode::FixOrNot;
+  FixMode          FixShellOrientationMode             = FixMode::FixOrNot;
+  FixMode          CreateOpenSolidMode                 = FixMode::NotFix;
+  FixMode          FixShellMode                        = FixMode::FixOrNot;
+  FixMode          FixFaceOrientationMode              = FixMode::FixOrNot;
+  FixMode          FixFaceMode                         = FixMode::FixOrNot;
+  FixMode          FixWireMode                         = FixMode::FixOrNot;
+  FixMode          FixOrientationMode                  = FixMode::FixOrNot;
+  FixMode          FixAddNaturalBoundMode              = FixMode::FixOrNot;
+  FixMode          FixMissingSeamMode                  = FixMode::FixOrNot;
+  FixMode          FixSmallAreaWireMode                = FixMode::FixOrNot;
+  FixMode          RemoveSmallAreaFaceMode             = FixMode::FixOrNot;
+  FixMode          FixIntersectingWiresMode            = FixMode::FixOrNot;
+  FixMode          FixLoopWiresMode                    = FixMode::FixOrNot;
+  FixMode          FixSplitFaceMode                    = FixMode::FixOrNot;
+  FixMode          AutoCorrectPrecisionMode            = FixMode::FixOrNot;
+  FixMode          ModifyTopologyMode                  = FixMode::NotFix;
+  FixMode          ModifyGeometryMode                  = FixMode::Fix;
+  FixMode          ClosedWireMode                      = FixMode::Fix;
+  FixMode          PreferencePCurveMode                = FixMode::Fix;
+  FixMode          FixReorderMode                      = FixMode::FixOrNot;
+  FixMode          FixSmallMode                        = FixMode::FixOrNot;
+  FixMode          FixConnectedMode                    = FixMode::FixOrNot;
+  FixMode          FixEdgeCurvesMode                   = FixMode::FixOrNot;
+  FixMode          FixDegeneratedMode                  = FixMode::FixOrNot;
+  FixMode          FixLackingMode                      = FixMode::FixOrNot;
+  FixMode          FixSelfIntersectionMode             = FixMode::FixOrNot;
+  FixMode          RemoveLoopMode                      = FixMode::FixOrNot;
+  FixMode          FixReversed2dMode                   = FixMode::FixOrNot;
+  FixMode          FixRemovePCurveMode                 = FixMode::FixOrNot;
+  FixMode          FixRemoveCurve3dMode                = FixMode::FixOrNot;
+  FixMode          FixAddPCurveMode                    = FixMode::FixOrNot;
+  FixMode          FixAddCurve3dMode                   = FixMode::FixOrNot;
+  FixMode          FixSeamMode                         = FixMode::FixOrNot;
+  FixMode          FixShiftedMode                      = FixMode::FixOrNot;
+  FixMode          FixEdgeSameParameterMode            = FixMode::NotFix;
+  FixMode          FixNotchedEdgesMode                 = FixMode::FixOrNot;
+  FixMode          FixTailMode                         = FixMode::NotFix;
+  FixMode          MaxTailAngle                        = FixMode::NotFix;
+  FixMode          MaxTailWidth                        = FixMode::FixOrNot;
+  FixMode          FixSelfIntersectingEdgeMode         = FixMode::FixOrNot;
+  FixMode          FixIntersectingEdgesMode            = FixMode::FixOrNot;
+  FixMode          FixNonAdjacentIntersectingEdgesMode = FixMode::FixOrNot;
+  FixMode          FixVertexPositionMode               = FixMode::NotFix;
+  FixMode          FixVertexToleranceMode              = FixMode::FixOrNot;
 };
 
 #endif // _DE_ShapeFixParameters_HeaderFile
index e38395aec5d0fdfaaa22b9599cdf7290c669942d..d8bf36688ea955196f5e9e36087ae36155b36b01 100644 (file)
 #include <ShapeProcess_Operator.hxx>
 #include <Standard_ErrorHandler.hxx>
 #include <Standard_Failure.hxx>
-#include <TCollection_AsciiString.hxx>
 #include <TColStd_SequenceOfAsciiString.hxx>
+#include <TCollection_AsciiString.hxx>
 
 static NCollection_DataMap<TCollection_AsciiString, Handle(ShapeProcess_Operator)> aMapOfOperators;
+
+namespace
+{
+  //! Simple RAII class to lock the scope of the current operation.
+  class ScopeLock
+  {
+  public:
+    //! Constructor.
+    //! Locks the scope of the current operation.
+    //! @param theContext the context to lock.
+    //! @param theScopeName the name of the scope to lock.
+    ScopeLock(ShapeProcess_Context& theContext, const char* theScopeName)
+      : myContext(theContext)
+    {
+      myContext.SetScope(theScopeName);
+    }
+
+    //! Destructor.
+    //! Unlocks the scope of the current operation.
+    ~ScopeLock()
+    {
+      myContext.UnSetScope();
+    }
+
+  private:
+    ShapeProcess_Context& myContext; //!< The context to lock.
+  };
+}
+
+
 //=======================================================================
 //function : RegisterOperator
 //purpose  : 
@@ -72,7 +102,7 @@ Standard_Boolean ShapeProcess::Perform (const Handle(ShapeProcess_Context)& cont
                                         const Standard_CString seq,
                                         const Message_ProgressRange& theProgress)
 {
-  context->SetScope ( seq );
+  ScopeLock aSequenceScope(*context, seq);
   
   // get description of the sequence
   TCollection_AsciiString sequence;
@@ -84,7 +114,6 @@ Standard_Boolean ShapeProcess::Perform (const Handle(ShapeProcess_Context)& cont
       Message_Msg SMSG3 ("SP.Sequence.Warn.NoSeq"); // Sequence %s not found
       context->Messenger()->Send (SMSG3 << seq, Message_Warning);
     }
-    context->UnSetScope();
     return Standard_False;
   }
   TColStd_SequenceOfAsciiString sequenceOfOperators;
@@ -131,7 +160,7 @@ Standard_Boolean ShapeProcess::Perform (const Handle(ShapeProcess_Context)& cont
       continue;
     }
     
-    context->SetScope ( oper.ToCString() );
+    ScopeLock anOperationScope(*context, oper.ToCString());
     try {
       OCC_CATCH_SIGNALS
       if (op->Perform(context, aRange))
@@ -142,9 +171,140 @@ Standard_Boolean ShapeProcess::Perform (const Handle(ShapeProcess_Context)& cont
       SMSG2 << oper << anException.GetMessageString();
       context->Messenger()->Send (SMSG2, Message_Alarm);
     }
-    context->UnSetScope();
   }
   
-  context->UnSetScope();
   return isDone;
 }
+
+//=======================================================================
+//function : Perform
+//purpose  :
+//=======================================================================
+Standard_Boolean ShapeProcess::Perform(const Handle(ShapeProcess_Context)& theContext,
+                                       const OperationsFlags&              theOperations,
+                                       const Message_ProgressRange&        theProgress)
+{
+  if (!theContext)
+  {
+    return Standard_False;
+  }
+
+  std::vector<std::pair<const char*, Handle(ShapeProcess_Operator)>> anOperators = getOperators(theOperations);
+  if (anOperators.empty())
+  {
+    return Standard_False;
+  }
+
+  Standard_Boolean anIsAnySuccess = Standard_False;
+  Message_ProgressScope aProgressScope(theProgress, nullptr, static_cast<Standard_Real>(anOperators.size()));
+  for (const auto& anOperator : anOperators)
+  {
+    const char* anOperationName = anOperator.first;
+    const Handle(ShapeProcess_Operator)& anOperation = anOperator.second;
+    Message_ProgressRange aProgressRange = aProgressScope.Next();
+    ScopeLock anOperationScope(*theContext, anOperationName); // Set operation scope.
+    try
+    {
+      OCC_CATCH_SIGNALS;
+      anIsAnySuccess |= anOperation->Perform(theContext, aProgressRange);
+    }
+    catch (const Standard_Failure& anException)
+    {
+      Message_Msg aMessage("SP.Sequence.Error.Except"); //Operator %s failed with exception %s
+      aMessage << anOperationName << anException.GetMessageString();
+      theContext->Messenger()->Send(aMessage, Message_Alarm);
+    }
+  }
+  return anIsAnySuccess;
+}
+
+//=======================================================================
+//function : getOperators
+//purpose  :
+//=======================================================================
+std::vector<std::pair<const char*, Handle(ShapeProcess_Operator)>> ShapeProcess::getOperators(const OperationsFlags& theFlags)
+{
+  std::vector<std::pair<const char*, Handle(ShapeProcess_Operator)>> aResult;
+  for (std::underlying_type<Operation>::type anOperation = Operation::First; anOperation < Operation::Count; ++anOperation)
+  {
+    if (theFlags.test(anOperation))
+    {
+      const char* anOperationName = toOperationName(static_cast<Operation>(anOperation));
+      if (!anOperationName)
+      {
+        continue;
+      }
+      Handle(ShapeProcess_Operator) anOperator;
+      if (FindOperator(anOperationName, anOperator))
+      {
+        aResult.emplace_back(anOperationName, anOperator);
+      }
+    }
+  }
+  return aResult;
+}
+
+//=======================================================================
+//function : toOperationName
+//purpose  :
+//=======================================================================
+const char* ShapeProcess::toOperationName(const Operation theOperation)
+{
+  switch (theOperation)
+  {
+    case Operation::DirectFaces:
+      return "DirectFaces";
+
+    case Operation::SameParameter:
+      return "SameParameter";
+
+    case Operation::SetTolerance:
+      return "SetTolerance";
+
+    case Operation::SplitAngle:
+      return "SplitAngle";
+
+    case Operation::BSplineRestriction:
+      return "BSplineRestriction";
+
+    case Operation::ElementaryToRevolution:
+      return "ElementaryToRevolution";
+
+    case Operation::SweptToElementary:
+      return "SweptToElementary";
+
+    case Operation::SurfaceToBSpline:
+      return "SurfaceToBSpline";
+
+    case Operation::ToBezier:
+      return "ToBezier";
+
+    case Operation::SplitContinuity:
+      return "SplitContinuity";
+
+    case Operation::SplitClosedFaces:
+      return "SplitClosedFaces";
+
+    case Operation::FixWireGaps:
+      return "FixWireGaps";
+
+    case Operation::FixFaceSize:
+      return "FixFaceSize";
+
+    case Operation::DropSmallSolids:
+      return "DropSmallSolids";
+
+    case Operation::DropSmallEdges:
+      return "DropSmallEdges";
+
+    case Operation::FixShape:
+      return "FixShape";
+
+    case Operation::SplitClosedEdges:
+      return "SplitClosedEdges";
+
+    case Operation::SplitCommonVertex:
+      return "SplitCommonVertex";
+  }
+  return nullptr;
+}
index 81e91ea6d88107c499dd97576480738e18b3978a..ac4d9fab94a1e3045b9a837fc3cc388e80eeb803 100644 (file)
 #ifndef _ShapeProcess_HeaderFile
 #define _ShapeProcess_HeaderFile
 
+#include <Message_ProgressRange.hxx>
 #include <Standard.hxx>
 #include <Standard_DefineAlloc.hxx>
 #include <Standard_Handle.hxx>
 
-#include <Message_ProgressRange.hxx>
+#include <bitset>
+#include <vector>
 
 class ShapeProcess_Operator;
 class ShapeProcess_Context;
@@ -34,10 +36,43 @@ class ShapeProcess_Context;
 class ShapeProcess 
 {
 public:
-
   DEFINE_STANDARD_ALLOC
 
+  //! Describes all available operations.
+  //! C++11 enum class is not used to allow implicit conversion to undelying type.
+  enum Operation : uint8_t
+  {
+    First = 0, // First operation index.
+    DirectFaces = First,
+    SameParameter,
+    SetTolerance,
+    SplitAngle,
+    BSplineRestriction,
+    ElementaryToRevolution,
+    SweptToElementary,
+    SurfaceToBSpline,
+    ToBezier,
+    SplitContinuity,
+    SplitClosedFaces,
+    FixWireGaps,
+    FixFaceSize,
+    DropSmallSolids,
+    DropSmallEdges,
+    FixShape,
+    SplitClosedEdges,
+    SplitCommonVertex,
+    Count // Number of operations.
+  };
+
+  // Bitset of operations. It is used to specify which operations should be performed.
+  // For example, to perform DirectFaces and SameParameter operations, use:
+  // ShapeProcess::OperationsFlags flags;
+  // flags.set(ShapeProcess::Operation::DirectFaces);
+  // flags.set(ShapeProcess::Operation::SameParameter);
+  // ShapeProcess::Perform(context, flags);
+  using OperationsFlags = std::bitset<Operation::Count>;
   
+public:
   //! Registers operator to make it visible for Performer
   Standard_EXPORT static Standard_Boolean RegisterOperator (const Standard_CString name, const Handle(ShapeProcess_Operator)& op);
   
@@ -52,6 +87,28 @@ public:
                     const Standard_CString seq,
                     const Message_ProgressRange& theProgress = Message_ProgressRange());
 
+  //! Performs a specified sequence of operators on @p theContext.
+  //! @param theContext Context to perform operations on. Contains the shape to process
+  //!        and processing parameters. If processing parameters are not set, default values are used.
+  //!        Parameters should be in a scope of operation, for example,
+  //!        instead of "FromSTEP.FixShape.Tolerance3d"        we should use just "FixShape.Tolerance3d".
+  //! @param theOperations Bitset of operations to perform.
+  //! @param theProgress Progress indicator.
+  //! @return true if at least one operation was performed, false otherwise.
+  Standard_EXPORT static Standard_Boolean Perform(const Handle(ShapeProcess_Context)& theContext,
+                                                  const OperationsFlags&              theOperations,
+                                                  const Message_ProgressRange&        theProgress = Message_ProgressRange());
+
+private:
+  //! Returns operators to be performed according to the specified flags.
+  //! @param theFlags Bitset of operations flags.
+  //! @return List of operators to perform: pairs of operator name and operator handle.
+  static std::vector<std::pair<const char*, Handle(ShapeProcess_Operator)>> getOperators(const OperationsFlags& theFlags);
+
+  //! Converts operation flag to its name.
+  //! @param theOperation Operation flag.
+  //! @return Operation name.
+  static const char* toOperationName(const Operation theOperation);
 };
 
 #endif // _ShapeProcess_HeaderFile
index a14e64a73d590d5d5d755e9cf33b5f7adb4f8238..f2d21f121d90c1b045f70eed56e8d38e0d37fabc 100644 (file)
@@ -2,3 +2,5 @@ XSAlgo.cxx
 XSAlgo.hxx
 XSAlgo_AlgoContainer.cxx
 XSAlgo_AlgoContainer.hxx
+XSAlgo_ShapeProcessor.cxx
+XSAlgo_ShapeProcessor.hxx
index 9eb4d009830728cbc3877843d67fa0661a2631eb..68f9cd950109991548dc3752f9ed85d75e0175a2 100644 (file)
 // Alternatively, this file may be used under the terms of Open CASCADE
 // commercial license or contractual agreement.
 
-
-#include <BRep_Builder.hxx>
-#include <BRep_Tool.hxx>
-#include <BRepBuilderAPI_MakeEdge.hxx>
-#include <Geom2d_Curve.hxx>
-#include <Geom_Curve.hxx>
-#include <Geom_Surface.hxx>
-#include <gp_Pnt.hxx>
-#include <gp_Pnt2d.hxx>
+#include <BRepTools_ReShape.hxx>
 #include <Interface_Static.hxx>
-#include <Message_Msg.hxx>
 #include <Resource_Manager.hxx>
 #include <ShapeAlgo.hxx>
 #include <ShapeAlgo_AlgoContainer.hxx>
 #include <ShapeAlgo_ToolContainer.hxx>
-#include <ShapeAnalysis_Edge.hxx>
-#include <ShapeBuild_Edge.hxx>
-#include <ShapeBuild_ReShape.hxx>
-#include <ShapeCustom.hxx>
 #include <ShapeExtend_MsgRegistrator.hxx>
-#include <ShapeFix_Edge.hxx>
 #include <ShapeFix_Shape.hxx>
-#include <ShapeProcess.hxx>
 #include <ShapeProcess_ShapeContext.hxx>
-#include <Standard_ErrorHandler.hxx>
-#include <Standard_Failure.hxx>
-#include <Standard_Transient.hxx>
-#include <Standard_Type.hxx>
-#include <TopExp.hxx>
-#include <TopoDS.hxx>
-#include <TopoDS_Edge.hxx>
-#include <TopoDS_Face.hxx>
-#include <TopoDS_Shape.hxx>
-#include <TopoDS_Vertex.hxx>
-#include <TopTools_DataMapOfShapeShape.hxx>
+#include <TopExp_Explorer.hxx>
 #include <Transfer_FinderProcess.hxx>
 #include <Transfer_TransientListBinder.hxx>
 #include <Transfer_TransientProcess.hxx>
 #include <TransferBRep.hxx>
 #include <TransferBRep_ShapeBinder.hxx>
 #include <TransferBRep_ShapeMapper.hxx>
-#include <UnitsMethods.hxx>
 #include <XSAlgo_AlgoContainer.hxx>
-#include <TopExp_Explorer.hxx>
+#include <XSAlgo_ShapeProcessor.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(XSAlgo_AlgoContainer,Standard_Transient)
 
@@ -64,10 +38,9 @@ IMPLEMENT_STANDARD_RTTIEXT(XSAlgo_AlgoContainer,Standard_Transient)
 //function : PrepareForTransfer
 //purpose  : 
 //=======================================================================
-
 void XSAlgo_AlgoContainer::PrepareForTransfer() const
 {
-  UnitsMethods::SetCasCadeLengthUnit(Interface_Static::IVal("xstep.cascade.unit"));
+  XSAlgo_ShapeProcessor::PrepareForTransfer();
 }
 
 //=======================================================================
@@ -114,15 +87,6 @@ TopoDS_Shape XSAlgo_AlgoContainer::ProcessShape(const TopoDS_Shape& theShape,
   aStr += ".exec.op";
   if (!aRsc->Find(aStr.ToCString()))
   {
-#ifdef OCCT_DEBUG
-    {
-      static Standard_Integer aTime = 0;
-      if (!aTime)
-        std::cout << "Warning: XSAlgo_AlgoContainer::ProcessShape(): Sequence " << aStr.ToCString() <<
-        " is not defined in " << thePrscfile << " resource; do default processing" << std::endl;
-      aTime++;
-    }
-#endif
     // if reading, do default ShapeFix
     if (!strncmp(thePseq, "read.", 5))
     {
@@ -147,10 +111,6 @@ TopoDS_Shape XSAlgo_AlgoContainer::ProcessShape(const TopoDS_Shape& theShape,
       }
       catch (Standard_Failure const& anException)
       {
-#ifdef OCCT_DEBUG
-        std::cout << "Error: XSAlgo_AlgoContainer::ProcessShape(): Exception in ShapeFix::Shape" << std::endl;
-        anException.Print(std::cout); std::cout << std::endl;
-#endif
         (void)anException;
       }
       return aContext->Result();
@@ -172,240 +132,17 @@ TopoDS_Shape XSAlgo_AlgoContainer::ProcessShape(const TopoDS_Shape& theShape,
   return aContext->Result();
 }
 
-//=======================================================================
-//function : PerformFixShape
-//purpose  : 
-//=======================================================================
-
-/*
-TopoDS_Shape XSAlgo_AlgoContainer::PerformFixShape(const TopoDS_Shape& S,
-                                                     const Handle(Transfer_TransientProcess)& TP,
-                                                     const Standard_Real Prec,
-                                                     const Standard_Real MaxTol) const
-{
-  if ( S.IsNull() ) return S;
-  
-  TopoDS_Shape shape = S;
-  // fixing shape
-  try {
-    OCC_CATCH_SIGNALS
-    Handle(ShapeFix_Shape) sfs = ShapeAlgo::AlgoContainer()->ToolContainer()->FixShape();
-    sfs->Init ( S );
-    sfs->SetMsgRegistrator ( new ShapeExtend_MsgRegistrator );
-    sfs->SetPrecision ( Prec );
-    sfs->SetMaxTolerance ( MaxTol );
-    sfs->FixFaceTool()->FixWireTool()->FixSameParameterMode() = Standard_False;
-    sfs->Perform();
-
-    shape = sfs->Shape();
-    
-    // to be removed when messages come
-    if ( shape == S || shape.IsNull() ) return S;
-    
-    // update map to reflect the substitutions
-    Handle(ShapeBuild_ReShape) context = sfs->Context();
-    const ShapeExtend_DataMapOfShapeListOfMsg& msgmap = 
-      Handle(ShapeExtend_MsgRegistrator)::DownCast (sfs->MsgRegistrator())->MapShape();
-    for ( Standard_Integer i=1; i <= TP->NbMapped(); i++ ) {
-      Handle(Transfer_Binder) bnd = TP->MapItem ( i );
-      Handle(TransferBRep_ShapeBinder) sb = Handle(TransferBRep_ShapeBinder)::DownCast ( bnd );
-      if ( sb.IsNull() || sb->Result().IsNull() ) continue;
-      
-      TopoDS_Shape orig = sb->Result();
-      
-      // update messages (messages must be taken from each level in the substitution map)
-      TopoDS_Shape cur, next = orig;
-      do {
-       cur = next;
-       Message_ListOfMsg msglist;
-       if (msgmap.IsBound (cur)) {
-         msglist = msgmap.Find (cur);
-         for (Message_ListIteratorOfListOfMsg iter (msglist); iter.More(); iter.Next()) {
-           const Message_Msg& msg = iter.Value();
-           sb->AddWarning (msg.Value(), msg.Original());
-         }
-       }
-       next = context->Value (cur);
-      } while (cur != next);
-
-      // update shapes
-      TopoDS_Shape res;
-      if ( ! context->Status ( orig, res, Standard_True ) ) continue;
-
-      sb->SetResult ( res );
-    }
-  }
-  catch (Standard_Failure) {
-#ifdef OCCT_DEBUG
-    std::cout << "Error: XSAlgo_AlgoContainer::PerformFixShape(): Exception in ShapeFix::Shape" << std::endl;
-#endif
-  }   
-  return shape;
-}
-*/
-
-// ============================================================================
-// Method  : MakeEdgeOnCurve
-// Purpose : for CheckPCurve
-// ============================================================================
-
-static TopoDS_Edge MakeEdgeOnCurve(const TopoDS_Edge& edge)
-{
-  TopoDS_Edge result;
-  //BRep_Builder B; // B not used - see below (skl)
-  Handle(Geom_Curve) C3d;
-  ShapeAnalysis_Edge sae;
-  Standard_Real cf, cl;
-  if (!sae.Curve3d (edge, C3d, cf, cl, Standard_False )) 
-    return result;
-  gp_Pnt PV1 = C3d->Value(cf);
-  gp_Pnt PV2 = C3d->Value(cl);
-  BRepBuilderAPI_MakeEdge mkEdge(C3d, PV1, PV2, cf, cl);
-//:S4136  Standard_Real tol = BRep_Tool::Tolerance (edge);
-  ShapeBuild_Edge SBE;          //skl 10.07.2001
-  SBE.SetRange3d(mkEdge,cf,cl); //skl 10.07.2001
-  result = mkEdge.Edge();
-//:S4136  B.UpdateEdge(result,tol);
-  return result;
-}
-
 //=======================================================================
 //function : CheckPCurve
 //purpose  : 
 //=======================================================================
 
-Standard_Boolean XSAlgo_AlgoContainer::CheckPCurve (const TopoDS_Edge& E,
-                                                   const TopoDS_Face& face,
-                                                   const Standard_Real preci,
-                                                   const Standard_Boolean isSeam) const
+Standard_Boolean XSAlgo_AlgoContainer::CheckPCurve(const TopoDS_Edge&     theEdge,
+                                                   const TopoDS_Face&     theFace,
+                                                   const Standard_Real    thePrecision,
+                                                   const Standard_Boolean theIsSeam) const
 {
-  Standard_Real w1, w2;  
-  Handle(Geom2d_Curve) thePC;
-  ShapeAnalysis_Edge sae;
-  if ( ! sae.PCurve (E, face, thePC, w1, w2, Standard_False ) ) {
-    return Standard_False;
-  }
-
-  // Check for pcurve longer than surface
-  Handle(Geom_Surface) surf = BRep_Tool::Surface(face);
-  Standard_Real UF,UL,VF,VL;
-  surf->Bounds (UF,UL,VF,VL);
-  gp_Pnt2d PUV1, PUV2;
-  PUV1 = thePC->Value(w1);
-  PUV2 = thePC->Value(w2);
-  //    Multi-periodique ? mieux vaut jeter (attention aux valeurs infinies)
-  Standard_Real DU = Abs (PUV1.X() - PUV2.X());
-  Standard_Real DV = Abs (PUV1.Y() - PUV2.Y());
-  if ( DU/8. > (UL/6. - UF/6.) || DV/8. > (VL/6. - VF/6.) ) {
-    ShapeBuild_Edge().RemovePCurve(E,face);
-#ifdef OCCT_DEBUG
-    std::cout<<"Removing pcurve periodic"<<std::endl;
-#endif      
-    return Standard_False;
-  }
-
-  // Second Check : 2D and 3D consistency (if the Pcurve has not been 
-  //                dropped)
-  //  On verifie aussi qu on ne s enroule pas trop ...
-  //  ex. : UVV en DEGRES sur une surface en RADIANS, recalee = 57 tours !
-
-  Handle(Geom_Curve) C3d;
-  Standard_Real cf1, cl1;
-  sae.Curve3d (E, C3d, cf1, cl1, Standard_False );
-
-  gp_Pnt P1 = surf->Value(PUV1.X(), PUV1.Y());
-  gp_Pnt P2 = surf->Value(PUV2.X(), PUV2.Y());
-  TopoDS_Vertex V1 = TopExp::FirstVertex(E);
-  TopoDS_Vertex V2 = TopExp::LastVertex(E);
-  gp_Pnt PV1 = ( C3d.IsNull() ? BRep_Tool::Pnt(V1) : C3d->Value(cf1) );
-  gp_Pnt PV2 = ( C3d.IsNull() ? BRep_Tool::Pnt(V2) : C3d->Value(cl1) );
-  Standard_Real Dist11 = PV1.Distance(P1), Dist22 = PV2.Distance(P2);
-    
-  if (!((Dist11 <= preci) && (Dist22 <= preci))) {
-    ShapeBuild_Edge().RemovePCurve(E,face);
-#ifdef OCCT_DEBUG
-    std::cout<<"Removing pcurve points"<<std::endl;
-#endif      
-    return Standard_False;
-  }
-
-  //
-  // pdn checking deviation between pcurve and 3D curve
-  //
-  
-  // Make temporary edge for analysis
-  if ( C3d.IsNull() ) return Standard_False;
-  TopoDS_Edge edge = MakeEdgeOnCurve(E);
-  
-  // fill it with pcurve(s)
-  BRep_Builder B;
-  Handle(Geom2d_Curve) seamPC;
-  if ( isSeam ) {
-    Standard_Real f, l;
-    TopoDS_Shape REdge = E.Reversed() ;
-    if ( ! sae.PCurve ( TopoDS::Edge ( REdge ), 
-                       face, seamPC, f, l, Standard_False ) ||
-        seamPC == thePC ) 
-      seamPC = Handle(Geom2d_Curve)::DownCast ( thePC->Copy() );
-    B.UpdateEdge ( edge, thePC, seamPC, face, 0.);
-  }
-  else B.UpdateEdge ( edge, thePC, face, 0.);
-  B.Range(edge,face,w1,w2);
-  B.SameRange(edge, Standard_False );
-  //:S4136
-  Standard_Integer SPmode = Interface_Static::IVal("read.stdsameparameter.mode");
-  if ( SPmode ) 
-    B.SameParameter (edge, Standard_False );
-
-  // call FixSP to see what it will do
-  Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
-  sfe->FixSameParameter(edge);
-  Standard_Real tol = BRep_Tool::Tolerance (edge);
-  //    Standard_Real tolV1 = BRep_Tool::Tolerance(TopExp::FirstVertex(edge));
-  //    Standard_Real tolV2 = BRep_Tool::Tolerance(TopExp::LastVertex(edge));                         
-  Standard_Boolean sr = BRep_Tool::SameRange ( edge );
-  Standard_Boolean sp = BRep_Tool::SameParameter ( edge );
-  
-  // if result is not nice, try to call projection and take the best
-  if ( tol > Min ( 1., 2.*preci ) || ! sr ) {
-    //pdn trying to recompute pcurve 
-    TopoDS_Edge edgePr = MakeEdgeOnCurve(E);
-    sfe->FixAddPCurve(edgePr, face, isSeam, preci);
-    sfe->FixSameParameter(edgePr);
-    Standard_Real tolPr = BRep_Tool::Tolerance (edgePr);
-    //pdn choose the best pcurve
-    if ( tolPr < tol || ! sr ) {
-      //       tolV1 = BRep_Tool::Tolerance(TopExp::FirstVertex(edgePr));
-      //       tolV2 = BRep_Tool::Tolerance(TopExp::LastVertex(edgePr));
-      sr = BRep_Tool::SameRange ( edgePr );
-      sp = BRep_Tool::SameParameter ( edgePr );
-      tol = tolPr;
-      edge = edgePr;
-    }
-  }
-  
-  // get corrected pcurve from the temporary edge, and put to original
-  sae.PCurve ( edge, face, thePC, w1, w2, Standard_False );
-  if ( isSeam ) {
-    Standard_Real f, l;
-    TopoDS_Shape REdge = edge.Reversed();
-    sae.PCurve ( TopoDS::Edge ( REdge ), face, seamPC, f, l, Standard_False );
-    if ( E.Orientation() == TopAbs_REVERSED ) //:abv 14.11.01: coneEl.sat loop
-      B.UpdateEdge ( E, seamPC, thePC, face, tol );
-    else 
-      B.UpdateEdge ( E, thePC, seamPC, face, tol );
-  }
-  else B.UpdateEdge ( E, thePC, face, tol );
-
-  B.UpdateVertex(V1,tol);
-  B.UpdateVertex(V2,tol);
-  B.Range(E,face, w1, w2);
-  if(BRep_Tool::SameRange(E))
-    B.SameRange( E, sr );
-  if(BRep_Tool::SameParameter(E))
-    B.SameParameter ( E, sp );
-  
-  return Standard_True;
+  return XSAlgo_ShapeProcessor::CheckPCurve(theEdge, theFace, thePrecision, theIsSeam);
 }
 
 //=======================================================================
@@ -526,15 +263,6 @@ void XSAlgo_AlgoContainer::MergeTransferInfo(const Handle(Transfer_FinderProcess
        if ( TransientListBinder->NbTransients() == 1 ) resBinder = new TransferBRep_ShapeBinder(sub);
        else if ( TransientListBinder->NbTransients() > 1 ) {
           resBinder->AddResult(TransientListBinder);
-//       resBinder->SetNext(TransientListBinder, Standard_True);
-#ifdef OCCT_DEBUG
-         std::cout<<"Info: TransientListBinder created for split shape"<<std::endl;
-       } 
-       else {
-         std::cout<<"Warning: XSAlgo_AlgoContainer::MergeTransferInfo() "
-           <<"No results were found for split shape. "<<std::endl;
-         //<<"Transfer_FinderProcess->NbMapped() = "<<FP->NbMapped()<<std::endl;
-#endif   
        }
       }
     }
index 6530b99c62adbab8e1d51a74b824aec766a7f6c3..b3669f5579121603844136aed6dcc36941383e4b 100644 (file)
@@ -68,7 +68,10 @@ public:
 
   //! Checks quality of pcurve of the edge on the given face,
   //! and corrects it if necessary.
-  Standard_EXPORT virtual Standard_Boolean CheckPCurve (const TopoDS_Edge& edge, const TopoDS_Face& face, const Standard_Real preci, const Standard_Boolean isSeam) const;
+  Standard_EXPORT virtual Standard_Boolean CheckPCurve (const TopoDS_Edge&     theEdge,
+                                                        const TopoDS_Face&     theFace,
+                                                        const Standard_Real    thePrecision,
+                                                        const Standard_Boolean theIsSeam) const;
   
   Standard_EXPORT virtual void MergeTransferInfo (const Handle(Transfer_TransientProcess)& TP, const Handle(Standard_Transient)& info, const Standard_Integer startTPitem = 1) const;
   
diff --git a/src/XSAlgo/XSAlgo_ShapeProcessor.cxx b/src/XSAlgo/XSAlgo_ShapeProcessor.cxx
new file mode 100644 (file)
index 0000000..a24c8af
--- /dev/null
@@ -0,0 +1,513 @@
+// Copyright (c) 2000-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include "XSAlgo_ShapeProcessor.hxx"
+
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <BRepTools_ReShape.hxx>
+#include <BRep_Builder.hxx>
+#include <BRep_Tool.hxx>
+#include <Geom_Curve.hxx>
+#include <Interface_Static.hxx>
+#include <Message_ListOfMsg.hxx>
+#include <Resource_Manager.hxx>
+#include <ShapeAnalysis_Edge.hxx>
+#include <ShapeBuild_Edge.hxx>
+#include <ShapeExtend_MsgRegistrator.hxx>
+#include <ShapeFix_Edge.hxx>
+#include <ShapeProcess_ShapeContext.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+#include <TransferBRep.hxx>
+#include <TransferBRep_ShapeBinder.hxx>
+#include <TransferBRep_ShapeMapper.hxx>
+#include <Transfer_FinderProcess.hxx>
+#include <Transfer_TransientListBinder.hxx>
+#include <Transfer_TransientProcess.hxx>
+#include <UnitsMethods.hxx>
+
+//=============================================================================
+
+XSAlgo_ShapeProcessor::XSAlgo_ShapeProcessor(const ParameterMap&          theParameters,
+                                             const DE_ShapeFixParameters& theShapeFixParameters)
+: myParameters(theParameters)
+{
+  FillParameterMap(theShapeFixParameters, myParameters);
+}
+
+//=============================================================================
+
+XSAlgo_ShapeProcessor::XSAlgo_ShapeProcessor(const DE_ShapeFixParameters& theParameters)
+{
+  ParameterMap aMap;
+  FillParameterMap(theParameters, aMap);
+  myParameters = aMap;
+}
+
+//=============================================================================
+
+TopoDS_Shape XSAlgo_ShapeProcessor::ProcessShape(const TopoDS_Shape&          theShape,
+                                                 const OperationsFlags&       theOperations,
+                                                 const Message_ProgressRange& theProgress)
+{
+  initializeContext(theShape);
+  return ShapeProcess::Perform(myContext, theOperations, theProgress) ? myContext->Result() : theShape;
+}
+
+//=============================================================================
+
+void XSAlgo_ShapeProcessor::initializeContext(const TopoDS_Shape& theShape)
+{
+  myContext = new ShapeProcess_ShapeContext(theShape, nullptr);
+  for (const auto& aParameter : myParameters)
+  {
+    myContext->ResourceManager()->SetResource(aParameter.first.c_str(), aParameter.second.c_str());
+  }
+  // Read and set detalization level.
+  auto aDetalizationLevelPtr = myParameters.find("DetalizationLevel");
+  if (aDetalizationLevelPtr != myParameters.end())
+  {
+    const TopAbs_ShapeEnum aDetalizationLevel = static_cast<TopAbs_ShapeEnum>(std::stoi(aDetalizationLevelPtr->second.c_str()));
+    myContext->SetDetalisation(aDetalizationLevel);
+  }
+  // Read and set non-manifold flag.
+  auto aNonManifoldPtr = myParameters.find("NonManifold");
+  if (aNonManifoldPtr != myParameters.end())
+  {
+    const Standard_Boolean aNonManifold = static_cast<Standard_Boolean>(std::stoi(aNonManifoldPtr->second.c_str()));
+    myContext->SetNonManifold(aNonManifold);
+  }
+}
+
+//=============================================================================
+
+void XSAlgo_ShapeProcessor::addMessages(const Handle(ShapeExtend_MsgRegistrator)& theMessages,
+                                        const TopoDS_Shape&                       theShape,
+                                        Handle(Transfer_Binder)&                  theBinder)
+{
+  if (theMessages.IsNull())
+  {
+    return;
+  }
+
+  const Message_ListOfMsg* aShapeMessages = theMessages->MapShape().Seek(theShape);
+  if (!aShapeMessages)
+  {
+    return;
+  }
+
+  for (Message_ListIteratorOfListOfMsg aMsgIter(*aShapeMessages); aMsgIter.More(); aMsgIter.Next())
+  {
+    const Message_Msg& aMessage = aMsgIter.Value();
+    theBinder->AddWarning(TCollection_AsciiString(aMessage.Value()).ToCString(),
+                          TCollection_AsciiString(aMessage.Original()).ToCString());
+  }
+}
+
+//=============================================================================
+
+void XSAlgo_ShapeProcessor::MergeTransferInfo(const Handle(Transfer_TransientProcess)& theTransientProcess,
+                                              const Standard_Integer                   theFirstTPItemIndex) const
+{
+  if (myContext.IsNull())
+  {
+    return;
+  }
+
+  const TopTools_DataMapOfShapeShape& aShapesMap = myContext->Map();
+  Handle(ShapeExtend_MsgRegistrator)  aMessages  = myContext->Messages();
+  if (aShapesMap.IsEmpty() && (aMessages.IsNull() || aMessages->MapShape().IsEmpty()))
+  {
+    return;
+  }
+
+  for (Standard_Integer i = std::max(theFirstTPItemIndex, 1); i <= theTransientProcess->NbMapped(); ++i)
+  {
+    Handle(TransferBRep_ShapeBinder) aShapeBinder = Handle(TransferBRep_ShapeBinder)::DownCast(theTransientProcess->MapItem(i));
+    if (aShapeBinder.IsNull() || aShapeBinder->Result().IsNull())
+    {
+      continue;
+    }
+
+    const TopoDS_Shape anOriginalShape = aShapeBinder->Result();
+
+    if (aShapesMap.IsBound(anOriginalShape))
+    {
+      aShapeBinder->SetResult(aShapesMap.Find(anOriginalShape));
+    }
+    else if (!anOriginalShape.Location().IsIdentity())
+    {
+      TopLoc_Location aNullLoc;
+      TopoDS_Shape    aTemporaryShape = anOriginalShape.Located(aNullLoc);
+      if (aShapesMap.IsBound(aTemporaryShape))
+      {
+        aShapeBinder->SetResult(aShapesMap.Find(aTemporaryShape));
+      }
+    }
+    else
+    {
+      // Some of edges may be modified.
+      BRepTools_ReShape aReShaper;
+      Standard_Boolean  aHasModifiedEdges = Standard_False;
+      // Remember modifications.
+      for (TopExp_Explorer anExpSE(anOriginalShape, TopAbs_EDGE); anExpSE.More(); anExpSE.Next())
+      {
+        if (aShapesMap.IsBound(anExpSE.Current()))
+        {
+          aHasModifiedEdges           = Standard_True;
+          TopoDS_Shape aModifiedShape = aShapesMap.Find(anExpSE.Current());
+          aReShaper.Replace(anExpSE.Current(), aModifiedShape);
+        }
+      }
+      // Apply modifications and store result in binder.
+      if (aHasModifiedEdges)
+      {
+        TopoDS_Shape aReshapedShape = aReShaper.Apply(anOriginalShape);
+        aShapeBinder->SetResult(aReshapedShape);
+      }
+    }
+
+    // update messages
+    addMessages(aMessages, anOriginalShape, aShapeBinder);
+  }
+}
+
+//=============================================================================
+
+void XSAlgo_ShapeProcessor::MergeTransferInfo(const Handle(Transfer_FinderProcess)& theFinderProcess) const
+{
+  if (myContext.IsNull())
+  {
+    return;
+  }
+
+  const TopTools_DataMapOfShapeShape& aShapesMap = myContext->Map();
+  Handle(ShapeExtend_MsgRegistrator)  aMessages  = myContext->Messages();
+
+  for (TopTools_DataMapIteratorOfDataMapOfShapeShape ShapeShapeIterator(aShapesMap); ShapeShapeIterator.More();
+       ShapeShapeIterator.Next())
+  {
+    const TopoDS_Shape anOriginalShape             = ShapeShapeIterator.Key();
+    const TopoDS_Shape aResultShape                = ShapeShapeIterator.Value();
+
+    Handle(TransferBRep_ShapeMapper) aResultMapper = TransferBRep::ShapeMapper(theFinderProcess, aResultShape);
+    Handle(Transfer_Binder)          aResultBinder = theFinderProcess->Find(aResultMapper);
+
+    if (aResultBinder.IsNull())
+    {
+      aResultBinder = new TransferBRep_ShapeBinder(aResultShape);
+      //if <orig> shape was split, put entities corresponding to new shapes
+      // into Transfer_TransientListBinder.
+      if (anOriginalShape.ShapeType() > aResultShape.ShapeType())
+      {
+        TopoDS_Shape                         aSubShape;
+        Handle(Transfer_TransientListBinder) aTransientListBinder = new Transfer_TransientListBinder;
+        for (TopoDS_Iterator aSubShapeIter(aResultShape); aSubShapeIter.More(); aSubShapeIter.Next())
+        {
+          const TopoDS_Shape      aCurrentSubShape = aSubShapeIter.Value();
+          Handle(Transfer_Finder) aSubShapeMapper  = TransferBRep::ShapeMapper(theFinderProcess, aCurrentSubShape);
+          if (aSubShapeMapper.IsNull())
+          {
+            continue;
+          }
+
+          Handle(Standard_Transient) aTransientResult = theFinderProcess->FindTransient(aSubShapeMapper);
+          if (aTransientResult.IsNull())
+          {
+            continue;
+          }
+          aTransientListBinder->AddResult(aTransientResult);
+          aSubShape = aCurrentSubShape;
+        }
+        if (aTransientListBinder->NbTransients() == 1)
+        {
+          aResultBinder = new TransferBRep_ShapeBinder(aSubShape);
+        }
+        else if (aTransientListBinder->NbTransients() > 1)
+        {
+          aResultBinder->AddResult(aTransientListBinder);
+        }
+      }
+    }
+
+    Handle(TransferBRep_ShapeMapper) anOriginalMapper = TransferBRep::ShapeMapper(theFinderProcess, anOriginalShape);
+    Handle(Transfer_Binder)          anOriginalBinder = theFinderProcess->Find(anOriginalMapper);
+    if (anOriginalBinder.IsNull())
+    {
+      theFinderProcess->Bind(anOriginalMapper, aResultBinder);
+    }
+    else
+    {
+      anOriginalBinder->AddResult(aResultBinder);
+    }
+
+    // update messages
+    addMessages(aMessages, anOriginalShape, aResultBinder);
+  }
+}
+
+//=============================================================================
+
+TopoDS_Edge XSAlgo_ShapeProcessor::MakeEdgeOnCurve(const TopoDS_Edge& aSourceEdge)
+{
+  TopoDS_Edge aResult;
+
+  Handle(Geom_Curve) aSourceGeomCurve;
+  Standard_Real      aStartParam;
+  Standard_Real      anEndParam;
+  ShapeAnalysis_Edge anEdgeAnalyzer;
+  if (!anEdgeAnalyzer.Curve3d(aSourceEdge, aSourceGeomCurve, aStartParam, anEndParam, Standard_False))
+  {
+    return aResult;
+  }
+  const gp_Pnt            aCurveStartPt = aSourceGeomCurve->Value(aStartParam);
+  const gp_Pnt            aCurveEndPt   = aSourceGeomCurve->Value(anEndParam);
+  BRepBuilderAPI_MakeEdge anEdgeMaker(aSourceGeomCurve, aCurveStartPt, aCurveEndPt, aStartParam, anEndParam);
+  ShapeBuild_Edge         SBE;
+  SBE.SetRange3d(anEdgeMaker, aStartParam, anEndParam);
+  aResult = anEdgeMaker.Edge();
+  return aResult;
+}
+
+//=============================================================================
+
+Standard_Boolean XSAlgo_ShapeProcessor::CheckPCurve(const TopoDS_Edge&     theEdge,
+                                                    const TopoDS_Face&     theFace,
+                                                    const Standard_Real    thePrecision,
+                                                    const Standard_Boolean theIsSeam)
+{
+  ShapeAnalysis_Edge anEdgeAnalyzer;
+
+  // Retrieve pcurve and its parameters.
+  Standard_Real        aCurve2DParam1;
+  Standard_Real        aCurve2DParam2;
+  Handle(Geom2d_Curve) aCurve2D;
+  if (!anEdgeAnalyzer.PCurve(theEdge, theFace, aCurve2D, aCurve2DParam1, aCurve2DParam2, Standard_False))
+  {
+    return Standard_False;
+  }
+
+  // Check for pcurve longer than surface.
+  Handle(Geom_Surface) aSurface = BRep_Tool::Surface(theFace);
+  Standard_Real        aFaceSurfaceU1, aFaceSurfaceU2, aFaceSurfaceV1, aFaceSurfaceV2;
+  aSurface->Bounds(aFaceSurfaceU1, aFaceSurfaceU2, aFaceSurfaceV1, aFaceSurfaceV2);
+  const gp_Pnt2d aCurve2DPoint1   = aCurve2D->Value(aCurve2DParam1);
+  const gp_Pnt2d aCurve2DPoint2   = aCurve2D->Value(aCurve2DParam2);
+  // Multi-periodic? Better to discard (beware of infinite values)
+  const Standard_Real anEdgeSpanX = Abs(aCurve2DPoint1.X() - aCurve2DPoint2.X());
+  const Standard_Real anEdgeSpanY = Abs(aCurve2DPoint1.Y() - aCurve2DPoint2.Y());
+  // So if span of pcurve along U or V is longer than 6/8 of the surface span, discard it.
+  // Why exactly 6/8? No idea, but it's the same as in the original code.
+  if (anEdgeSpanX / 8. > (aFaceSurfaceU2 / 6. - aFaceSurfaceU1 / 6.)
+      || anEdgeSpanY / 8. > (aFaceSurfaceV2 / 6. - aFaceSurfaceV1 / 6.))
+  {
+    ShapeBuild_Edge().RemovePCurve(theEdge, theFace);
+    return Standard_False;
+  }
+
+  // Second Check: 2D and 3D consistency (if the Pcurve has not been dropped)
+  // We also check that it does not wrap around too much...
+  // Example: UVV in DEGREES on a surface in RADIANS, adjusted = 57 turns!
+  Handle(Geom_Curve) aCurve3D;
+  Standard_Real      aCurve3DParam1;
+  Standard_Real      aCurve3DParam2;
+  anEdgeAnalyzer.Curve3d(theEdge, aCurve3D, aCurve3DParam1, aCurve3DParam2, Standard_False);
+
+  const gp_Pnt        aCurve3DPoint1 = aSurface->Value(aCurve2DPoint1.X(), aCurve2DPoint1.Y());
+  const gp_Pnt        aCurve3DPoint2 = aSurface->Value(aCurve2DPoint2.X(), aCurve2DPoint2.Y());
+  const TopoDS_Vertex aVertex1       = TopExp::FirstVertex(theEdge);
+  const TopoDS_Vertex aVertex2       = TopExp::LastVertex(theEdge);
+  const gp_Pnt        aPV1           = (aCurve3D.IsNull() ? BRep_Tool::Pnt(aVertex1) : aCurve3D->Value(aCurve3DParam1));
+  const gp_Pnt        aPV2           = (aCurve3D.IsNull() ? BRep_Tool::Pnt(aVertex2) : aCurve3D->Value(aCurve3DParam2));
+  const Standard_Real aDist11        = aPV1.Distance(aCurve3DPoint1);
+  const Standard_Real aDist22        = aPV2.Distance(aCurve3DPoint2);
+
+  if (!((aDist11 <= thePrecision) && (aDist22 <= thePrecision)))
+  {
+    ShapeBuild_Edge().RemovePCurve(theEdge, theFace);
+    return Standard_False;
+  }
+
+  //
+  // pdn checking deviation between pcurve and 3D curve
+  //
+
+  // Make temporary edge for analysis
+  if (aCurve3D.IsNull())
+  {
+    return Standard_False;
+  }
+  TopoDS_Edge aTmpEdge = MakeEdgeOnCurve(theEdge);
+
+  // fill it with pcurve(s)
+  BRep_Builder         aBuilder;
+  Handle(Geom2d_Curve) aSeamPCurve;
+  if (theIsSeam)
+  {
+    Standard_Real aSeamPCurveParam1;
+    Standard_Real aSeamPCurveParam2;
+    TopoDS_Edge   aReversedEdge = TopoDS::Edge(theEdge.Reversed());
+    if (!anEdgeAnalyzer.PCurve(aReversedEdge, theFace, aSeamPCurve, aSeamPCurveParam1, aSeamPCurveParam2, Standard_False)
+        || aSeamPCurve == aCurve2D)
+    {
+      aSeamPCurve = Handle(Geom2d_Curve)::DownCast(aCurve2D->Copy());
+    }
+    aBuilder.UpdateEdge(aTmpEdge, aCurve2D, aSeamPCurve, theFace, 0.);
+  }
+  else
+  {
+    aBuilder.UpdateEdge(aTmpEdge, aCurve2D, theFace, 0.);
+  }
+  aBuilder.Range(aTmpEdge, theFace, aCurve2DParam1, aCurve2DParam2);
+  aBuilder.SameRange(aTmpEdge, Standard_False);
+  if (Interface_Static::IVal("read.stdsameparameter.mode"))
+  {
+    aBuilder.SameParameter(aTmpEdge, Standard_False);
+  }
+
+  // call FixSP to see what it will do
+  Handle(ShapeFix_Edge) anEdgeFixer = new ShapeFix_Edge;
+  anEdgeFixer->FixSameParameter(aTmpEdge);
+  Standard_Real    aTolerance         = BRep_Tool::Tolerance(aTmpEdge);
+  Standard_Boolean aSameRangeFlag     = BRep_Tool::SameRange(aTmpEdge);
+  Standard_Boolean aSameParameterFlag = BRep_Tool::SameParameter(aTmpEdge);
+
+  // if result is not nice, try to call projection and take the best
+  if (aTolerance > Min(1., 2. * thePrecision) || !aSameRangeFlag)
+  {
+    //pdn trying to recompute pcurve
+    TopoDS_Edge anEdgePr = MakeEdgeOnCurve(theEdge);
+    anEdgeFixer->FixAddPCurve(anEdgePr, theFace, theIsSeam, thePrecision);
+    anEdgeFixer->FixSameParameter(anEdgePr);
+    const Standard_Real aTolerancePr = BRep_Tool::Tolerance(anEdgePr);
+    //pdn choose the best pcurve
+    if (aTolerancePr < aTolerance || !aSameRangeFlag)
+    {
+      aSameRangeFlag     = BRep_Tool::SameRange(anEdgePr);
+      aSameParameterFlag = BRep_Tool::SameParameter(anEdgePr);
+      aTolerance         = aTolerancePr;
+      aTmpEdge           = anEdgePr;
+    }
+  }
+
+  // get corrected pcurve from the temporary edge, and put to original
+  anEdgeAnalyzer.PCurve(aTmpEdge, theFace, aCurve2D, aCurve2DParam1, aCurve2DParam2, Standard_False);
+  if (theIsSeam)
+  {
+    Standard_Real aReversedTmpEdgeParam1;
+    Standard_Real aReversedTmpEdgeParam2;
+    TopoDS_Edge   aReversedTmpEdge = TopoDS::Edge(aTmpEdge.Reversed());
+    anEdgeAnalyzer
+      .PCurve(aReversedTmpEdge, theFace, aSeamPCurve, aReversedTmpEdgeParam1, aReversedTmpEdgeParam2, Standard_False);
+    if (theEdge.Orientation() == TopAbs_REVERSED) //:abv 14.11.01: coneEl.sat loop
+    {
+      aBuilder.UpdateEdge(theEdge, aSeamPCurve, aCurve2D, theFace, aTolerance);
+    }
+    else
+    {
+      aBuilder.UpdateEdge(theEdge, aCurve2D, aSeamPCurve, theFace, aTolerance);
+    }
+  }
+  else
+  {
+    aBuilder.UpdateEdge(theEdge, aCurve2D, theFace, aTolerance);
+  }
+
+  aBuilder.UpdateVertex(aVertex1, aTolerance);
+  aBuilder.UpdateVertex(aVertex2, aTolerance);
+  aBuilder.Range(theEdge, theFace, aCurve2DParam1, aCurve2DParam2);
+  if (BRep_Tool::SameRange(theEdge))
+  {
+    aBuilder.SameRange(theEdge, aSameRangeFlag);
+  }
+  if (BRep_Tool::SameParameter(theEdge))
+  {
+    aBuilder.SameParameter(theEdge, aSameParameterFlag);
+  }
+
+  return Standard_True;
+}
+
+//=============================================================================
+
+void XSAlgo_ShapeProcessor::FillParameterMap(const DE_ShapeFixParameters&         theParameters,
+                                             XSAlgo_ShapeProcessor::ParameterMap& theMap)
+{
+  // Helper lambda to convert enum to string.
+  auto makeString = [](const DE_ShapeFixParameters::FixMode theMode)
+  {
+    return std::to_string(static_cast<std::underlying_type<DE_ShapeFixParameters::FixMode>::type>(theMode));
+  };
+
+  theMap.emplace("ShapeFix.Tolerance3d", std::to_string(theParameters.Tolerance3d));
+  theMap.emplace("ShapeFix.MaxTolerance3d", std::to_string(theParameters.MaxTolerance3d));
+  theMap.emplace("ShapeFix.MinTolerance3d", std::to_string(theParameters.MinTolerance3d));
+  theMap.emplace("DetalizationLevel", std::to_string(theParameters.DetalizationLevel));
+  theMap.emplace("NonManifold", std::to_string(theParameters.NonManifold));
+  theMap.emplace("ShapeFix.FixFreeShellMode", makeString(theParameters.FixFreeShellMode));
+  theMap.emplace("ShapeFix.FixFreeFaceMode", makeString(theParameters.FixFreeFaceMode));
+  theMap.emplace("ShapeFix.FixFreeWireMode", makeString(theParameters.FixFreeWireMode));
+  theMap.emplace("ShapeFix.FixSameParameterMode", makeString(theParameters.FixSameParameterMode));
+  theMap.emplace("ShapeFix.FixSolidMode", makeString(theParameters.FixSolidMode));
+  theMap.emplace("ShapeFix.FixShellOrientationMode", makeString(theParameters.FixShellOrientationMode));
+  theMap.emplace("ShapeFix.CreateOpenSolidMode", makeString(theParameters.CreateOpenSolidMode));
+  theMap.emplace("ShapeFix.FixShellMode", makeString(theParameters.FixShellMode));
+  theMap.emplace("ShapeFix.FixFaceOrientationMode", makeString(theParameters.FixFaceOrientationMode));
+  theMap.emplace("ShapeFix.FixFaceMode", makeString(theParameters.FixFaceMode));
+  theMap.emplace("ShapeFix.FixWireMode", makeString(theParameters.FixWireMode));
+  theMap.emplace("ShapeFix.FixOrientationMode", makeString(theParameters.FixOrientationMode));
+  theMap.emplace("ShapeFix.FixAddNaturalBoundMode", makeString(theParameters.FixAddNaturalBoundMode));
+  theMap.emplace("ShapeFix.FixMissingSeamMode", makeString(theParameters.FixMissingSeamMode));
+  theMap.emplace("ShapeFix.FixSmallAreaWireMode", makeString(theParameters.FixSmallAreaWireMode));
+  theMap.emplace("ShapeFix.RemoveSmallAreaFaceMode", makeString(theParameters.RemoveSmallAreaFaceMode));
+  theMap.emplace("ShapeFix.FixIntersectingWiresMode", makeString(theParameters.FixIntersectingWiresMode));
+  theMap.emplace("ShapeFix.FixLoopWiresMode", makeString(theParameters.FixLoopWiresMode));
+  theMap.emplace("ShapeFix.FixSplitFaceMode", makeString(theParameters.FixSplitFaceMode));
+  theMap.emplace("ShapeFix.AutoCorrectPrecisionMode", makeString(theParameters.AutoCorrectPrecisionMode));
+  theMap.emplace("ShapeFix.ModifyTopologyMode", makeString(theParameters.ModifyTopologyMode));
+  theMap.emplace("ShapeFix.ModifyGeometryMode", makeString(theParameters.ModifyGeometryMode));
+  theMap.emplace("ShapeFix.ClosedWireMode", makeString(theParameters.ClosedWireMode));
+  theMap.emplace("ShapeFix.PreferencePCurveMode", makeString(theParameters.PreferencePCurveMode));
+  theMap.emplace("ShapeFix.FixReorderMode", makeString(theParameters.FixReorderMode));
+  theMap.emplace("ShapeFix.FixSmallMode", makeString(theParameters.FixSmallMode));
+  theMap.emplace("ShapeFix.FixConnectedMode", makeString(theParameters.FixConnectedMode));
+  theMap.emplace("ShapeFix.FixEdgeCurvesMode", makeString(theParameters.FixEdgeCurvesMode));
+  theMap.emplace("ShapeFix.FixDegeneratedMode", makeString(theParameters.FixDegeneratedMode));
+  theMap.emplace("ShapeFix.FixLackingMode", makeString(theParameters.FixLackingMode));
+  theMap.emplace("ShapeFix.FixSelfIntersectionMode", makeString(theParameters.FixSelfIntersectionMode));
+  theMap.emplace("ShapeFix.RemoveLoopMode", makeString(theParameters.RemoveLoopMode));
+  theMap.emplace("ShapeFix.FixReversed2dMode", makeString(theParameters.FixReversed2dMode));
+  theMap.emplace("ShapeFix.FixRemovePCurveMode", makeString(theParameters.FixRemovePCurveMode));
+  theMap.emplace("ShapeFix.FixRemoveCurve3dMode", makeString(theParameters.FixRemoveCurve3dMode));
+  theMap.emplace("ShapeFix.FixAddPCurveMode", makeString(theParameters.FixAddPCurveMode));
+  theMap.emplace("ShapeFix.FixAddCurve3dMode", makeString(theParameters.FixAddCurve3dMode));
+  theMap.emplace("ShapeFix.FixSeamMode", makeString(theParameters.FixSeamMode));
+  theMap.emplace("ShapeFix.FixShiftedMode", makeString(theParameters.FixShiftedMode));
+  theMap.emplace("ShapeFix.FixEdgeSameParameterMode", makeString(theParameters.FixEdgeSameParameterMode));
+  theMap.emplace("ShapeFix.FixNotchedEdgesMode", makeString(theParameters.FixNotchedEdgesMode));
+  theMap.emplace("ShapeFix.FixTailMode", makeString(theParameters.FixTailMode));
+  theMap.emplace("ShapeFix.MaxTailAngle", makeString(theParameters.MaxTailAngle));
+  theMap.emplace("ShapeFix.MaxTailWidth", makeString(theParameters.MaxTailWidth));
+  theMap.emplace("ShapeFix.FixSelfIntersectingEdgeMode", makeString(theParameters.FixSelfIntersectingEdgeMode));
+  theMap.emplace("ShapeFix.FixIntersectingEdgesMode", makeString(theParameters.FixIntersectingEdgesMode));
+  theMap.emplace("ShapeFix.FixNonAdjacentIntersectingEdgesMode", makeString(theParameters.FixNonAdjacentIntersectingEdgesMode));
+  theMap.emplace("ShapeFix.FixVertexPositionMode", makeString(theParameters.FixVertexPositionMode));
+  theMap.emplace("ShapeFix.FixVertexToleranceMode", makeString(theParameters.FixVertexToleranceMode));
+}
+
+//=============================================================================
+
+void XSAlgo_ShapeProcessor::PrepareForTransfer()
+{
+  UnitsMethods::SetCasCadeLengthUnit(Interface_Static::IVal("xstep.cascade.unit"));
+}
diff --git a/src/XSAlgo/XSAlgo_ShapeProcessor.hxx b/src/XSAlgo/XSAlgo_ShapeProcessor.hxx
new file mode 100644 (file)
index 0000000..29f8b37
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright (c) 2000-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _XSAlgo_ShapeProcessor_HeaderFile
+#define _XSAlgo_ShapeProcessor_HeaderFile
+
+#include <DE_ShapeFixParameters.hxx>
+#include <ShapeProcess.hxx>
+#include <TopAbs_ShapeEnum.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+
+#include <unordered_map>
+
+class ShapeProcess_ShapeContext;
+class ShapeExtend_MsgRegistrator;
+class Transfer_TransientProcess;
+class Transfer_FinderProcess;
+class Transfer_Binder;
+
+//! Shape Processing module.
+//! Allows to define and apply general Shape Processing as a customizable sequence of operators.
+class XSAlgo_ShapeProcessor
+{
+public:
+  using OperationsFlags = ShapeProcess::OperationsFlags;
+  using ParameterMap    = std::unordered_map<std::string, std::string>;
+
+public:
+  //! Constructor.
+  //! @param theParameters Pre-filled parameter map to be used in the processing.
+  //! @param theShapeFixParameters Shape healing parameters to be used in the processing.
+  //!        If @p theParameters has some shape healing values, they will override the
+  //!        corresponding values from @p theShapeFixParameters.
+  Standard_EXPORT XSAlgo_ShapeProcessor(const ParameterMap&          theParameters,
+                                        const DE_ShapeFixParameters& theShapeFixParameters = {});
+
+  //! Constructor.
+  //! @param theParameters Parameters to be used in the processing.
+  Standard_EXPORT XSAlgo_ShapeProcessor(const DE_ShapeFixParameters& theParameters);
+
+  //! Process the shape by applying the specified operations.
+  //! @param theShape Shape to process.
+  //! @param theOperations Operations to be performed.
+  //! @param theProgress Progress indicator.
+  //! @return Processed shape. May be the same as the input shape if no modifications were made.
+  Standard_EXPORT TopoDS_Shape ProcessShape(const TopoDS_Shape&          theShape,
+                                            const OperationsFlags&       theOperations,
+                                            const Message_ProgressRange& theProgress);
+
+  //! Get the context of the last processing.
+  //! Only valid after the ProcessShape() method was called.
+  //! @return Shape context.
+  Handle(ShapeProcess_ShapeContext) GetContext() { return myContext; }
+
+  //! Merge the results of the shape processing with the transfer process.
+  //! @param theTransientProcess Transfer process to merge with.
+  //! @param theFirstTPItemIndex Index of the first item in the transfer process to merge with.
+  Standard_EXPORT void MergeTransferInfo(const Handle(Transfer_TransientProcess)& theTransientProcess,
+                                         const Standard_Integer                   theFirstTPItemIndex) const;
+
+  //! Merge the results of the shape processing with the finder process.
+  //! @param theFinderProcess Finder process to merge with.
+  Standard_EXPORT void MergeTransferInfo(const Handle(Transfer_FinderProcess)& theFinderProcess) const;
+
+  //! Check quality of pcurve of the edge on the given face, and correct it if necessary.
+  //! @param theEdge Edge to check.
+  //! @param theFace Face on which the edge is located.
+  //! @param thePrecision Precision to use for checking.
+  //! @param theIsSeam Flag indicating whether the edge is a seam edge.
+  //! @return True if the pcurve was corrected, false if it was dropped.
+  Standard_EXPORT static Standard_Boolean CheckPCurve(const TopoDS_Edge&     theEdge,
+                                                      const TopoDS_Face&     theFace,
+                                                      const Standard_Real    thePrecision,
+                                                      const Standard_Boolean theIsSeam);
+
+  //! Fill the parameter map with the values from the specified parameters.
+  //! @param theParameters Parameters to be used in the processing.
+  //! @param theMap Map to fill.
+  Standard_EXPORT static void FillParameterMap(const DE_ShapeFixParameters& theParameters, ParameterMap& theMap);
+
+  //! The function is designed to set the length unit for the application before performing a
+  //! transfer operation. It ensures that the length unit is correctly configured based on the
+  //! value associated with the key "xstep.cascade.unit".
+  Standard_EXPORT static void PrepareForTransfer();
+
+private:
+  //! Initialize the context with the specified shape.
+  //! @param theShape Shape to process.
+  void initializeContext(const TopoDS_Shape& theShape);
+
+  //! Add messages from the specified shape to the transfer binder.
+  //! @param theMessages Container with messages.
+  //! @param theShape Shape to get messages from.
+  //! @param theBinder Transfer binder to add messages to.
+  static void addMessages(const Handle(ShapeExtend_MsgRegistrator)& theMessages,
+                          const TopoDS_Shape&                       theShape,
+                          Handle(Transfer_Binder)&                  theBinder);
+
+  //! Create a new edge with the same geometry as the source edge.
+  //! @param theSourceEdge Source edge.
+  //! @return New edge with the same geometry.
+  static TopoDS_Edge MakeEdgeOnCurve(const TopoDS_Edge& aSourceEdge);
+
+private:
+  ParameterMap                      myParameters; //!< Parameters to be used in the processing.
+  Handle(ShapeProcess_ShapeContext) myContext;    //!< Shape context.
+};
+
+#endif // _XSAlgo_ShapeProcessor_HeaderFile