From ed87a1f7c81ec39992aff1f463d73dc81e5791e0 Mon Sep 17 00:00:00 2001 From: eap Date: Wed, 10 Dec 2014 19:07:28 +0300 Subject: [PATCH] 22752: [EDF] Provide explicit feedback on what has been done by Shape Processing operation + 22757: [EDF] Vertex on Edge --- allow projecting several points at once --- .../examples/repairing_operations_ex10.py | 7 +- doc/salome/gui/GEOM/images/divedgebypoint.png | Bin 18671 -> 18727 bytes doc/salome/gui/GEOM/images/repair8.png | Bin 19410 -> 17829 bytes .../input/add_point_on_edge_operation.doc | 12 +- idl/GEOM_Gen.idl | 38 +++-- src/GEOM/GEOM_Function.cxx | 60 ++++++- src/GEOM/GEOM_Function.hxx | 14 +- src/GEOMGUI/GEOM_msg_en.ts | 16 +- src/GEOMImpl/CMakeLists.txt | 1 + src/GEOMImpl/GEOMImpl_HealingDriver.cxx | 150 ++++++++++++++++-- src/GEOMImpl/GEOMImpl_HealingDriver.hxx | 10 +- src/GEOMImpl/GEOMImpl_IHealing.hxx | 15 +- src/GEOMImpl/GEOMImpl_IHealingOperations.cxx | 53 +++++-- src/GEOMImpl/GEOMImpl_IHealingOperations.hxx | 13 +- src/GEOMImpl/GEOMImpl_PolylineDumper.cxx | 2 +- src/GEOM_I/CMakeLists.txt | 1 + src/GEOM_I/GEOM_IHealingOperations_i.cc | 40 ++++- src/GEOM_I/GEOM_IHealingOperations_i.hh | 4 +- src/GEOM_SWIG/geomBuilder.py | 16 +- src/RepairGUI/RepairGUI.cxx | 95 +++++++++++ src/RepairGUI/RepairGUI.h | 6 +- .../RepairGUI_ChangeOrientationDlg.cxx | 19 ++- src/RepairGUI/RepairGUI_CloseContourDlg.cxx | 12 +- src/RepairGUI/RepairGUI_DivideEdgeDlg.cxx | 91 ++++++----- src/RepairGUI/RepairGUI_DivideEdgeDlg.h | 2 +- src/RepairGUI/RepairGUI_LimitToleranceDlg.cxx | 11 +- src/RepairGUI/RepairGUI_RemoveHolesDlg.cxx | 11 +- src/RepairGUI/RepairGUI_RemoveIntWiresDlg.cxx | 12 +- src/RepairGUI/RepairGUI_ShapeProcessDlg.cxx | 11 +- src/RepairGUI/RepairGUI_SuppressFacesDlg.cxx | 12 +- src/ShHealOper/CMakeLists.txt | 1 + .../ShHealOper_ChangeOrientation.cxx | 11 ++ src/ShHealOper/ShHealOper_CloseContour.cxx | 13 +- src/ShHealOper/ShHealOper_EdgeDivide.cxx | 21 ++- src/ShHealOper/ShHealOper_FillHoles.cxx | 3 + src/ShHealOper/ShHealOper_ModifStats.hxx | 78 +++++++++ .../ShHealOper_RemoveInternalWires.cxx | 3 + src/ShHealOper/ShHealOper_ShapeProcess.cxx | 72 +++++++-- src/ShHealOper/ShHealOper_ShapeProcess.hxx | 4 +- src/ShHealOper/ShHealOper_Tool.cxx | 1 + src/ShHealOper/ShHealOper_Tool.hxx | 37 +++-- 41 files changed, 802 insertions(+), 176 deletions(-) create mode 100644 src/ShHealOper/ShHealOper_ModifStats.hxx diff --git a/doc/salome/examples/repairing_operations_ex10.py b/doc/salome/examples/repairing_operations_ex10.py index c2dbc160f..6b8e4280e 100644 --- a/doc/salome/examples/repairing_operations_ex10.py +++ b/doc/salome/examples/repairing_operations_ex10.py @@ -33,10 +33,11 @@ for point in edge_points: # Variant 2: using DivideEdgeByPoint() box = geompy.MakeBox(0,0,0, 10,10,10, theName="box") -p = geompy.MakeVertex( 3, -2, 1, theName="point to project" ) -edge = geompy.GetEdgeNearPoint( box, p, theName="edge to split") +p1 = geompy.MakeVertex( 3, -2, 1, theName="point 1 to project" ) +p2 = geompy.MakeVertex( 7, -2, 1, theName="point 2 to project" ) +edge = geompy.GetEdgeNearPoint( box, p1, theName="edge to split") -div = geompy.DivideEdgeByPoint( box, edge, p, theName="box (edge divided)") +div = geompy.DivideEdgeByPoint( box, edge, [p1, p2], theName="box (edge divided)") salome.sg.updateObjBrowser(1) diff --git a/doc/salome/gui/GEOM/images/divedgebypoint.png b/doc/salome/gui/GEOM/images/divedgebypoint.png index cb80833cdf8a5f33b4b3e336c49d07aeb57a5a1b..4258a1657e61ebcd9ce6b04466930ef286d3069f 100644 GIT binary patch literal 18727 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 HEcAZ>h3FDc diff --git a/doc/salome/gui/GEOM/images/repair8.png b/doc/salome/gui/GEOM/images/repair8.png index 5c30a97603cb9c2924d1071a9427888f5340fd37..c15f31345dbc4bc90e6a66bf2d4bab7fb2858091 100644 GIT binary patch literal 17829 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 Point on Edge in the Main Menu select Repair - > Add Point on Edge. -This operation splits an edge in two new edges. +This operation splits an edge in two or more new edges. This operation is available in OCC Viewer only. The \b Result will be a \b GEOM_Object. @@ -41,17 +41,17 @@ The \b Result will be a \b GEOM_Object. \image html repair8.png \n\n -
  • We can select a point that will be projected to the selected - edge to find the location of the new vertex. +
  • We can select several points that will be projected to the selected + edge to find the location of new vertices.

    - TUI Command: geompy.DivideEdgeByPoint(Shape, Edge, Point) + TUI Command: geompy.DivideEdgeByPoint(Shape, Edge, Points)

    • \em Shape is a shape which contains an edge to be divided
    • \em Edge is an edge to be divided (or it's ID, if it is = -1, then \em Shape should be an edge itself).
    • -
    • \em Point is a point to project to \a Edge.
    • +
    • \em Points is a list of points to project to \a Edge.
    - \b Arguments: Name + 1 Edge + 1 Point. + \b Arguments: Name + 1 Edge + 1 or more Points. \image html divedgebypoint.png diff --git a/idl/GEOM_Gen.idl b/idl/GEOM_Gen.idl index 0880b9fd6..dc9cf2f92 100644 --- a/idl/GEOM_Gen.idl +++ b/idl/GEOM_Gen.idl @@ -205,7 +205,6 @@ module GEOM SI_ALL // all interferences }; - /*! * \brief Object creation parameters * @@ -214,7 +213,6 @@ module GEOM struct Parameter { string name; - //any value; string value; }; typedef sequence Parameters; @@ -225,6 +223,16 @@ module GEOM Parameters params; }; + /*! + * \brief Reporting on shape healing + */ + struct ModifInfo + { + string name; // what changed + long count; // how many times + }; + typedef sequence ModifStatistics; + typedef sequence string_array; typedef sequence short_array; @@ -2042,7 +2050,7 @@ module GEOM * \param theEdges List of edges for gluing. * \return New GEOM_Object containing copies of theShapes without some edges. */ - GEOM_Object MakeGlueEdgesByList (in ListOfGO theShape, + GEOM_Object MakeGlueEdgesByList (in ListOfGO theShapes, in double theTolerance, in ListOfGO theEdges); @@ -3785,7 +3793,7 @@ module GEOM /*! * Sewing of the given object. - * \param theObject Shape to be processed. + * \param theObjects Shapes to be processed. * \param theTolerance Required tolerance value. * \return New GEOM_Object, containing processed shape. */ @@ -3793,7 +3801,7 @@ module GEOM /*! * Sewing of the given object. Allows non-manifold sewing. - * \param theObject Shape to be processed. + * \param theObjects Shapes to be processed. * \param theTolerance Required tolerance value. * \return New GEOM_Object, containing processed shape. */ @@ -3822,17 +3830,17 @@ module GEOM in double theValue, in boolean isByParameter); /*! - * \brief Addition of a point to a given edge of \a theObject by projecting - * another point to the given edge. + * \brief Addition of points to a given edge of \a theObject by projecting + * other points to the given edge. * \param theObject Shape to be processed. * \param theEdgeIndex Index of edge to be divided within theObject's shape, * if -1, then theObject itself is the edge. - * \param thePoint Point to project to theEdgeIndex-th edge. + * \param thePoints Points to project to theEdgeIndex-th edge. * \return New GEOM_Object, containing the processed shape. */ GEOM_Object DivideEdgeByPoint (in GEOM_Object theObject, in short theEdgeIndex, - in GEOM_Object thePoint); + in ListOfGO thePoints); /*! * \brief Suppress the vertices in the wire in case if adjacent edges are C1 continuous. @@ -3846,13 +3854,13 @@ module GEOM /*! * \brief Get a list of wires (wrapped in GEOM_Object-s), - * that constitute a free boundary of the given shape. - * \param theObject Shapes to get free boundary of. + * that constitute a free boundary of the given shapes. + * \param theObjects Shapes to get free boundary of. * \param theClosedWires Output. Closed wires on the free boundary of the given shape. * \param theOpenWires Output. Open wires on the free boundary of the given shape. * \return FALSE, if an error(s) occured during the method execution. */ - boolean GetFreeBoundary (in ListOfGO theObjects, + boolean GetFreeBoundary (in ListOfGO theObjects, out ListOfGO theClosedWires, out ListOfGO theOpenWires); @@ -3872,6 +3880,12 @@ module GEOM */ GEOM_Object LimitTolerance (in GEOM_Object theObject, in double theTolerance); + + /*! + * \brief Return information on what has been done by the last called healing method. + * \return ModifStatistics, information container. + */ + ModifStatistics GetStatistics(); }; // # GEOM_IInsertOperations: diff --git a/src/GEOM/GEOM_Function.cxx b/src/GEOM/GEOM_Function.cxx index 458e0a0bc..e96a3a52c 100644 --- a/src/GEOM/GEOM_Function.cxx +++ b/src/GEOM/GEOM_Function.cxx @@ -62,6 +62,8 @@ #include #include +#include + #include #include // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC @@ -76,6 +78,7 @@ #define HISTORY_LABEL 4 #define SUBSHAPES_LABEL 5 // 0020756: GetGroups #define NAMING_LABEL 6 // 0020750: Naming during STEP import +#define CALLBACK_LABEL 1 // TDataStd_Comment #ifdef KEEP_ORIENTATION_0021251 #define ORIENTATION_LABEL 7 // 0021251: TNaming_NamedShape doesn't store orientation @@ -124,7 +127,7 @@ Handle(GEOM_Function) GEOM_Function::GetFunction(const TDF_Label& theEntry) */ //============================================================================= GEOM_Function::GEOM_Function(const TDF_Label& theEntry, const Standard_GUID& theGUID, int theType) -: _label(theEntry) + : _label(theEntry), _isCallBackData(false) { TFunction_Function::Set(theEntry, theGUID); TDataStd_Integer::Set(theEntry, theType); @@ -139,6 +142,21 @@ GEOM_Function::GEOM_Function(const TDF_Label& theEntry, const Standard_GUID& the aRoot->Append(aNode); } +//================================================================================ +/*! + * \brief + * + * + */ +//================================================================================ + +GEOM_Function::~GEOM_Function() +{ + if ( _isCallBackData ) { + _label.FindChild( CALLBACK_LABEL ).ForgetAttribute( TDataStd_Comment::GetID() ); + } +} + //================================================================================ /*! * \brief Retuns true if this function is the last one in the study @@ -928,5 +946,45 @@ TDF_Label GEOM_Function::GetNamingEntry (const Standard_Boolean create) return _label.FindChild(NAMING_LABEL, create); } +//================================================================================ +/*! + * Save a pointer to a data holder intended to pass temporary data Driver -> Operation. + * This method should be called by Operation to set the data holder. + * An instance of GEOM_Function that sets the data holder will remove the + * corresponding OCAF attribute at it's destruction + */ +//================================================================================ + +void GEOM_Function::SetCallBackData( void* data ) +{ + std::ostringstream strm; + strm << (long long) data; + TCollection_ExtendedString string( strm.str().c_str() ); + + TDF_Label aChild = _label.FindChild(CALLBACK_LABEL); + TDataStd_Comment::Set(aChild, string); + + _isCallBackData = true; // I will remove TDataStd_Comment at destruction +} + +//================================================================================ +/*! + * Returns a pointer to a data holder intended to pass data Driver -> Operation. + * This method should be called by Driver to get the data holder to fill it in. + * Returns NULL if the Operation have not set the data holder. + */ +//================================================================================ + +void* GEOM_Function::GetCallBackData() +{ + Handle(TDataStd_Comment) aComment; + TDF_Label aChild = _label.FindChild( CALLBACK_LABEL ); + if(!aChild.FindAttribute(TDataStd_Comment::GetID(), aComment)) return NULL; + TCollection_AsciiString string( aComment->Get() ); + + long long address = atoll( string.ToCString() ); + return reinterpret_cast ( address ); +} + IMPLEMENT_STANDARD_HANDLE (GEOM_Function, Standard_Transient); IMPLEMENT_STANDARD_RTTIEXT(GEOM_Function, Standard_Transient ); diff --git a/src/GEOM/GEOM_Function.hxx b/src/GEOM/GEOM_Function.hxx index 688324dae..3d2a4ec96 100644 --- a/src/GEOM/GEOM_Function.hxx +++ b/src/GEOM/GEOM_Function.hxx @@ -56,7 +56,7 @@ public: Standard_EXPORT GEOM_Function(const TDF_Label& theEntry, const Standard_GUID& theGUID, int theType); - Standard_EXPORT ~GEOM_Function() {} + Standard_EXPORT ~GEOM_Function(); Standard_EXPORT TDF_Label GetOwnerEntry(); @@ -152,6 +152,17 @@ public: //Returns a list of references to other function arguments at position thePosition Standard_EXPORT Handle(TColStd_HSequenceOfTransient) GetReferenceList (int thePosition); + // Save a pointer to a data holder intended to pass data Driver -> Operation. + // This method should be called by Operation to set the data holder. + // An instance of GEOM_Function that sets the data holder will remove the + // corresponding OCAF attribute at it's destruction + Standard_EXPORT void SetCallBackData( void* data ); + + // Returns a pointer to a data holder intended to pass data Driver -> Operation. + // This method should be called by Driver to get the data holder to fill it in. + // Returns NULL if the Operation have not set the data holder. + Standard_EXPORT void* GetCallBackData(); + //Sets a TopoDS_Shape argument at position thePosition //void SetShape(int thePosition, const TopoDS_Shape& theShape); @@ -190,6 +201,7 @@ public: TDF_Label _label; bool _isDone; + bool _isCallBackData; }; #endif diff --git a/src/GEOMGUI/GEOM_msg_en.ts b/src/GEOMGUI/GEOM_msg_en.ts index b5e65a385..31679839b 100644 --- a/src/GEOMGUI/GEOM_msg_en.ts +++ b/src/GEOMGUI/GEOM_msg_en.ts @@ -44,7 +44,7 @@ Do you still want to delete these objects? DEVIDE_EDGE_BY_PROJ_POINT - Point to project + Points to project ERROR_SHAPE_TYPE @@ -569,7 +569,7 @@ Please, select face, shell or solid and try again GEOM_DIVIDE_EDGE_TITLE - Addition of point + Addition of points GEOM_DX @@ -5232,6 +5232,18 @@ shells and solids on the other hand. GEOM_NO_SHAPES_SELECTED There are no shapes that meet filtering parameters + + GEOM_HEALING_STATS_TITLE + What is done + + + GEOM_HEALING_STATS_COL_1 + Count + + + GEOM_HEALING_STATS_COL_2 + Modication + GeometryGUI diff --git a/src/GEOMImpl/CMakeLists.txt b/src/GEOMImpl/CMakeLists.txt index 3822d2912..42b467403 100755 --- a/src/GEOMImpl/CMakeLists.txt +++ b/src/GEOMImpl/CMakeLists.txt @@ -33,6 +33,7 @@ INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/src/SKETCHER ${PROJECT_SOURCE_DIR}/src/ARCHIMEDE ${PROJECT_SOURCE_DIR}/src/XAO + ${PROJECT_SOURCE_DIR}/src/ShHealOper ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/src/GEOMImpl/GEOMImpl_HealingDriver.cxx b/src/GEOMImpl/GEOMImpl_HealingDriver.cxx index 48bca4095..51154eb63 100644 --- a/src/GEOMImpl/GEOMImpl_HealingDriver.cxx +++ b/src/GEOMImpl/GEOMImpl_HealingDriver.cxx @@ -216,6 +216,8 @@ Standard_Boolean GEOMImpl_HealingDriver::ShapeProcess (GEOMImpl_IHealing* theHI, if (!aHealer.isDone()) raiseNotDoneExeption( ShHealOper_NotError ); + SaveStatistics( aHealer ); + return Standard_True; } @@ -223,9 +225,9 @@ Standard_Boolean GEOMImpl_HealingDriver::ShapeProcess (GEOMImpl_IHealing* theHI, //function : SupressFaces //purpose : //======================================================================= -void SuppressFacesRec (const TopTools_SequenceOfShape& theShapesFaces, - const TopoDS_Shape& theOriginalShape, - TopoDS_Shape& theOutShape) +void GEOMImpl_HealingDriver::SuppressFacesRec (const TopTools_SequenceOfShape& theShapesFaces, + const TopoDS_Shape& theOriginalShape, + TopoDS_Shape& theOutShape) const { if ((theOriginalShape.ShapeType() != TopAbs_COMPOUND && theOriginalShape.ShapeType() != TopAbs_COMPSOLID)) @@ -307,6 +309,21 @@ Standard_Boolean GEOMImpl_HealingDriver::SuppressFaces (GEOMImpl_IHealing* theHI theOutShape = GEOMImpl_GlueDriver::GlueFaces(aSh, Precision::Confusion(), Standard_True); } } + // count removed faces + TopTools_IndexedMapOfShape faces; + TopExp::MapShapes(theOriginalShape, TopAbs_FACE, faces); + int nbBefore = faces.Extent(); + faces.Clear(); + TopExp::MapShapes(theOutShape, TopAbs_FACE, faces); + int nbAfter = faces.Extent(); + + if ( nbAfter < nbBefore ) + { + ShHealOper_Tool tool; + ShHealOper_ModifStats& stats = tool.GetStatistics(); + stats.AddModif( "Face removed", nbBefore - nbAfter ); + SaveStatistics( tool ); + } return Standard_True; } @@ -347,6 +364,8 @@ Standard_Boolean GEOMImpl_HealingDriver::CloseContour (GEOMImpl_IHealing* theHI, else raiseNotDoneExeption( aHealer.GetErrorStatus() ); + SaveStatistics( aHealer ); + return aResult; } @@ -383,6 +402,8 @@ Standard_Boolean GEOMImpl_HealingDriver::RemoveIntWires (GEOMImpl_IHealing* theH else raiseNotDoneExeption( aHealer.GetErrorStatus() ); + SaveStatistics( aHealer ); + return aResult; } @@ -419,6 +440,8 @@ Standard_Boolean GEOMImpl_HealingDriver::RemoveHoles (GEOMImpl_IHealing* theHI, else raiseNotDoneExeption( aHealer.GetErrorStatus() ); + SaveStatistics( aHealer ); + return aResult; } @@ -464,6 +487,8 @@ Standard_Boolean GEOMImpl_HealingDriver::Sew (GEOMImpl_IHealing* theHI, else raiseNotDoneExeption( aHealer.GetErrorStatus() ); + SaveStatistics( aHealer ); + return aResult; } @@ -546,12 +571,21 @@ Standard_Boolean GEOMImpl_HealingDriver::AddPointOnEdge (GEOMImpl_IHealing* the { Handle(TColStd_HSequenceOfTransient) funs = theHI->GetShapes(); if ( !funs.IsNull() && funs->Length() > 0 ) { - Handle(GEOM_Function) fun = Handle(GEOM_Function)::DownCast( funs->Value(1) ); - if ( !fun.IsNull() ) - pointToProject = fun->GetValue(); + TopoDS_Compound vCompound; + BRep_Builder builder; + builder.MakeCompound( vCompound ); + pointToProject = vCompound; + for ( int ind = 1; ind <= funs->Length(); ind++) + { + Handle(GEOM_Function) vFun = Handle(GEOM_Function)::DownCast(funs->Value(ind)); + TopoDS_Shape vertex = vFun->GetValue(); + if ( vertex.IsNull() ) + Standard_NullObject::Raise("Null vertex given"); + builder.Add( vCompound, vertex ); + } } } - + ShHealOper_EdgeDivide aHealer (theOriginalShape); Standard_Boolean aResult = Standard_False; @@ -579,6 +613,8 @@ Standard_Boolean GEOMImpl_HealingDriver::AddPointOnEdge (GEOMImpl_IHealing* the else raiseNotDoneExeption( aHealer.GetErrorStatus() ); + SaveStatistics( aHealer ); + return aResult; } @@ -600,6 +636,8 @@ Standard_Boolean GEOMImpl_HealingDriver::ChangeOrientation (GEOMImpl_IHealing* t else raiseNotDoneExeption( aHealer.GetErrorStatus() ); + SaveStatistics( aHealer ); + return aResult; } @@ -617,9 +655,10 @@ void GEOMImpl_HealingDriver::LimitTolerance (GEOMImpl_IHealing* theHI, // 1. Make a copy to prevent the original shape changes. TopoDS_Shape aShapeCopy; - TColStd_IndexedDataMapOfTransientTransient aMapTShapes; - TNaming_CopyShape::CopyTool(theOriginalShape, aMapTShapes, aShapeCopy); - + { + TColStd_IndexedDataMapOfTransientTransient aMapTShapes; + TNaming_CopyShape::CopyTool(theOriginalShape, aMapTShapes, aShapeCopy); + } // 2. Limit tolerance. ShapeFix_ShapeTolerance aSFT; aSFT.LimitTolerance(aShapeCopy, aTol, aTol, TopAbs_SHAPE); @@ -632,6 +671,68 @@ void GEOMImpl_HealingDriver::LimitTolerance (GEOMImpl_IHealing* theHI, BRepCheck_Analyzer ana (theOutShape, Standard_True); if (!ana.IsValid()) StdFail_NotDone::Raise("Non valid shape result"); + + // 4. Collect statistics + { + ShHealOper_Tool tool; + ShHealOper_ModifStats& stats = tool.GetStatistics(); + + int nb[3] = { 0,0,0 }; + TopTools_IndexedMapOfShape aShapes; + TopExp::MapShapes( theOutShape, TopAbs_VERTEX, aShapes); + for ( int i = 1; i <= aShapes.Extent(); ++i ) + { + const TopoDS_Vertex& v = TopoDS::Vertex( aShapes( i )); + double tol = BRep_Tool::Tolerance( v ); + if ( tol < aTol ) nb[0]++; + else if ( tol > aTol ) nb[2]++; + else nb[1]++; + } + if ( nb[0] > 0 ) + stats.AddModif( "Tolerance of vertex decreased for shape validity", nb[0] ); + if ( nb[1] > 0 ) + stats.AddModif( "Tolerance of vertex limited as requested", nb[1] ); + if ( nb[2] > 0 ) + stats.AddModif( "Tolerance of vertex increased for shape validity", nb[2] ); + + nb[0] = nb[1] = nb[2] = 0; + aShapes.Clear(); + TopExp::MapShapes( theOutShape, TopAbs_EDGE, aShapes); + for ( int i = 1; i <= aShapes.Extent(); ++i ) + { + const TopoDS_Edge& e = TopoDS::Edge( aShapes( i )); + double tol = BRep_Tool::Tolerance( e ); + if ( tol < aTol ) nb[0]++; + else if ( tol > aTol ) nb[2]++; + else nb[1]++; + } + if ( nb[0] > 0 ) + stats.AddModif( "Tolerance of edge decreased for shape validity", nb[0] ); + if ( nb[1] > 0 ) + stats.AddModif( "Tolerance of edge limited as requested", nb[1] ); + if ( nb[2] > 0 ) + stats.AddModif( "Tolerance of edge increased for shape validity", nb[2] ); + + nb[0] = nb[1] = nb[2] = 0; + aShapes.Clear(); + TopExp::MapShapes( theOutShape, TopAbs_FACE, aShapes); + for ( int i = 1; i <= aShapes.Extent(); ++i ) + { + const TopoDS_Face& f = TopoDS::Face( aShapes( i )); + double tol = BRep_Tool::Tolerance( f ); + if ( tol < aTol ) nb[0]++; + else if ( tol > aTol ) nb[2]++; + else nb[1]++; + } + if ( nb[0] > 0 ) + stats.AddModif( "Tolerance of face decreased for shape validity", nb[0] ); + if ( nb[1] > 0 ) + stats.AddModif( "Tolerance of face limited as requested", nb[1] ); + if ( nb[2] > 0 ) + stats.AddModif( "Tolerance of face increased for shape validity", nb[2] ); + + SaveStatistics( tool ); + } } //======================================================================= @@ -971,7 +1072,7 @@ GetCreationInformation(std::string& theOperationName, AddParam( theParams, "Edge", "#" ) << aCI.GetIndex() << " of " << aCI.GetOriginal(); else AddParam( theParams, "Edge", aCI.GetOriginal() ); - AddParam( theParams, "Point", aCI.GetShapes() ); + AddParam( theParams, "Points", aCI.GetShapes() ); break; case CHANGE_ORIENTATION: theOperationName = "CHANGE_ORIENTATION"; @@ -997,6 +1098,33 @@ GetCreationInformation(std::string& theOperationName, return true; } + +//================================================================================ +/*! + * \brief Pass a record of what is done to the operation + */ +//================================================================================ + +void GEOMImpl_HealingDriver::SaveStatistics( const ShHealOper_Tool& healer, bool add ) const +{ + if ( healer.GetStatistics().GetData().empty() ) + return; + + if (Label().IsNull()) return; + + Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label()); + if (aFunction.IsNull()) return; + + GEOMImpl_IHealing HI (aFunction); + ShHealOper_ModifStats * stats = HI.GetStatistics(); + if ( !stats ) return; + + if ( add ) + stats->Add( healer.GetStatistics() ); + else + *stats = healer.GetStatistics(); +} + IMPLEMENT_STANDARD_HANDLE (GEOMImpl_HealingDriver,GEOM_BaseDriver); IMPLEMENT_STANDARD_RTTIEXT (GEOMImpl_HealingDriver,GEOM_BaseDriver); diff --git a/src/GEOMImpl/GEOMImpl_HealingDriver.hxx b/src/GEOMImpl/GEOMImpl_HealingDriver.hxx index 5784acd14..f738be6f4 100644 --- a/src/GEOMImpl/GEOMImpl_HealingDriver.hxx +++ b/src/GEOMImpl/GEOMImpl_HealingDriver.hxx @@ -61,10 +61,12 @@ #include #endif -class GEOMImpl_IHealing; +#include "GEOM_BaseDriver.hxx" +class GEOMImpl_IHealing; +class ShHealOper_Tool; +class TopTools_SequenceOfShape; -#include "GEOM_BaseDriver.hxx" DEFINE_STANDARD_HANDLE( GEOMImpl_HealingDriver, GEOM_BaseDriver ); @@ -99,6 +101,9 @@ DEFINE_STANDARD_RTTI( GEOMImpl_HealingDriver ) private: Standard_Boolean ShapeProcess ( GEOMImpl_IHealing*, const TopoDS_Shape&, TopoDS_Shape& ) const; Standard_Boolean SuppressFaces ( GEOMImpl_IHealing*, const TopoDS_Shape&, TopoDS_Shape& ) const; + void SuppressFacesRec (const TopTools_SequenceOfShape& theShapesFaces, + const TopoDS_Shape& theOriginalShape, + TopoDS_Shape& theOutShape) const; Standard_Boolean CloseContour ( GEOMImpl_IHealing*, const TopoDS_Shape&, TopoDS_Shape& ) const; Standard_Boolean RemoveIntWires( GEOMImpl_IHealing*, const TopoDS_Shape&, TopoDS_Shape& ) const; Standard_Boolean RemoveHoles ( GEOMImpl_IHealing*, const TopoDS_Shape&, TopoDS_Shape& ) const; @@ -108,6 +113,7 @@ private: Standard_Boolean ChangeOrientation( GEOMImpl_IHealing*, const TopoDS_Shape&, TopoDS_Shape& ) const; void LimitTolerance( GEOMImpl_IHealing*, const TopoDS_Shape&, TopoDS_Shape& ) const; + void SaveStatistics( const ShHealOper_Tool& healer, bool add=false ) const; }; #endif diff --git a/src/GEOMImpl/GEOMImpl_IHealing.hxx b/src/GEOMImpl/GEOMImpl_IHealing.hxx index d21962155..06e354db2 100755 --- a/src/GEOMImpl/GEOMImpl_IHealing.hxx +++ b/src/GEOMImpl/GEOMImpl_IHealing.hxx @@ -25,6 +25,7 @@ #include #include #include "TColStd_HSequenceOfTransient.hxx" +#include class GEOMImpl_IHealing { @@ -41,7 +42,8 @@ public: ARG_DEV_EDGE_VALUE = 8, ARG_IS_BY_PARAMETER = 9, ARG_SUBSHAPE_INDEX = 10, - ARG_LIST_SHAPES = 11 + ARG_LIST_SHAPES = 11, + ARG_STATISTICS = 4 }; GEOMImpl_IHealing(Handle(GEOM_Function) theFunction): _func(theFunction) {} @@ -91,6 +93,17 @@ public: funs->Prepend( GetOriginal() ); return funs; } + + void SetStatistics( ShHealOper_ModifStats * ms ) + { + if ( ms ) ms->Clear(); + _func->SetCallBackData( (void*) ms ); + } + ShHealOper_ModifStats * GetStatistics() + { + return (ShHealOper_ModifStats*) _func->GetCallBackData(); + } + private: Handle(GEOM_Function) _func; }; diff --git a/src/GEOMImpl/GEOMImpl_IHealingOperations.cxx b/src/GEOMImpl/GEOMImpl_IHealingOperations.cxx index 3a2b13305..3b8ab1147 100644 --- a/src/GEOMImpl/GEOMImpl_IHealingOperations.cxx +++ b/src/GEOMImpl/GEOMImpl_IHealingOperations.cxx @@ -25,7 +25,6 @@ #endif #include -#include #include #include @@ -35,6 +34,8 @@ #include #include #include +#include +#include #include @@ -43,12 +44,10 @@ #include #include -#include #include #include #include #include -#include #include #include #include @@ -64,6 +63,7 @@ GEOMImpl_IHealingOperations::GEOMImpl_IHealingOperations (GEOM_Engine* theEngine, int theDocID) : GEOM_IOperations(theEngine, theDocID) { + myModifStats = new ShHealOper_ModifStats; MESSAGE("GEOMImpl_IHealingOperations::GEOMImpl_IHealingOperations"); } @@ -74,6 +74,7 @@ GEOMImpl_IHealingOperations::GEOMImpl_IHealingOperations (GEOM_Engine* theEngine //============================================================================= GEOMImpl_IHealingOperations::~GEOMImpl_IHealingOperations() { + delete myModifStats; MESSAGE("GEOMImpl_IHealingOperations::~GEOMImpl_IHealingOperations"); } @@ -134,6 +135,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::ShapeProcess (Handle(GEOM_Objec HI.SetParameters( theParams ); HI.SetValues( theValues ); } + HI.SetStatistics( myModifStats ); //Compute the translation try { @@ -341,6 +343,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::SuppressFaces GEOMImpl_IHealing HI (aFunction); HI.SetFaces(theFaces); HI.SetOriginal(aLastFunction); + HI.SetStatistics( myModifStats ); //Compute the translation try { @@ -409,6 +412,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::CloseContour HI.SetWires( theWires ); HI.SetIsCommonVertex( isCommonVertex ); HI.SetOriginal( aLastFunction ); + HI.SetStatistics( myModifStats ); //Compute the translation try { @@ -476,6 +480,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::RemoveIntWires GEOMImpl_IHealing HI(aFunction); HI.SetWires( theWires ); HI.SetOriginal( aLastFunction ); + HI.SetStatistics( myModifStats ); //Compute the translation try { @@ -542,6 +547,7 @@ 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 { @@ -616,6 +622,7 @@ GEOMImpl_IHealingOperations::Sew (std::list& theObjects, HI.SetTolerance( theTolerance ); HI.SetOriginal( theObjects.front()->GetLastFunction() ); objects->Remove(1); HI.SetShapes( objects ); + HI.SetStatistics( myModifStats ); //Compute the result try { @@ -682,6 +689,7 @@ GEOMImpl_IHealingOperations::RemoveInternalFaces (std::list< Handle(GEOM_Object) GEOMImpl_IHealing HI (aFunction); HI.SetOriginal( theSolids.front()->GetLastFunction() ); objects->Remove(1); HI.SetShapes( objects ); + HI.SetStatistics( myModifStats ); //Compute the result try { @@ -741,6 +749,7 @@ 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 { @@ -770,21 +779,26 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::DivideEdge (Handle(GEOM_Object) */ //============================================================================= Handle(GEOM_Object) -GEOMImpl_IHealingOperations::DivideEdgeByPoint (Handle(GEOM_Object) theObject, - int theIndex, - Handle(GEOM_Object) thePoint) +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() || thePoint.IsNull()) + if (theObject.IsNull() || thePoints.empty() ) return NULL; Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction(); - Handle(GEOM_Function) aPointFunc = thePoint->GetLastFunction(); - if (aLastFunction.IsNull() || aPointFunc.IsNull()) + 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( GetDocID(), GEOM_COPY ); @@ -798,12 +812,11 @@ GEOMImpl_IHealingOperations::DivideEdgeByPoint (Handle(GEOM_Object) theObject, // prepare "data container" class IHealing GEOMImpl_IHealing HI(aFunction); - HI.SetIndex( theIndex ); - HI.SetOriginal( aLastFunction ); + HI.SetIndex ( theIndex ); + HI.SetOriginal ( aLastFunction ); + HI.SetShapes ( aPointFunc ); - Handle(TColStd_HSequenceOfTransient) funSeq = new TColStd_HSequenceOfTransient; - funSeq->Append( aPointFunc ); - HI.SetShapes( funSeq ); + HI.SetStatistics( myModifStats ); //Compute the translation try { @@ -822,7 +835,7 @@ GEOMImpl_IHealingOperations::DivideEdgeByPoint (Handle(GEOM_Object) theObject, //Make a Python command GEOM::TPythonDump(aFunction) << aNewObject << " = geompy.DivideEdgeByPoint(" << theObject - << ", " << theIndex << ", " << thePoint << ")"; + << ", " << theIndex << ", " << thePoints << ")"; SetErrorCode(OK); return aNewObject; @@ -853,6 +866,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; @@ -1039,6 +1053,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 @@ -1051,6 +1068,7 @@ 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 @@ -1106,6 +1124,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 @@ -1118,6 +1139,7 @@ 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 @@ -1176,6 +1198,7 @@ Handle(GEOM_Object) GEOMImpl_IHealingOperations::LimitTolerance (Handle(GEOM_Obj GEOMImpl_IHealing HI (aFunction); HI.SetOriginal(aLastFunction); HI.SetTolerance(theTolerance); + HI.SetStatistics( myModifStats ); // Compute try { diff --git a/src/GEOMImpl/GEOMImpl_IHealingOperations.hxx b/src/GEOMImpl/GEOMImpl_IHealingOperations.hxx index e2af51e10..df2952a9a 100644 --- a/src/GEOMImpl/GEOMImpl_IHealingOperations.hxx +++ b/src/GEOMImpl/GEOMImpl_IHealingOperations.hxx @@ -32,6 +32,8 @@ #include +class ShHealOper_ModifStats; + class GEOMImpl_IHealingOperations : public GEOM_IOperations { public: Standard_EXPORT GEOMImpl_IHealingOperations(GEOM_Engine* theEngine, int theDocID); @@ -81,9 +83,9 @@ class GEOMImpl_IHealingOperations : public GEOM_IOperations { double theValue, bool isByParameter ); - Standard_EXPORT Handle(GEOM_Object) DivideEdgeByPoint( Handle(GEOM_Object) theObject, - int theIndex, - Handle(GEOM_Object) thePoint ); + Standard_EXPORT Handle(GEOM_Object) DivideEdgeByPoint( Handle(GEOM_Object) theObject, + int theIndex, + std::list& thePoint ); Standard_EXPORT Handle(GEOM_Object) FuseCollinearEdgesWithinWire (Handle(GEOM_Object) theWire, @@ -102,6 +104,11 @@ class GEOMImpl_IHealingOperations : public GEOM_IOperations { Standard_EXPORT Handle(GEOM_Object) LimitTolerance( Handle(GEOM_Object) theObject, double theTolerance ); + const ShHealOper_ModifStats* GetStatistics() { return myModifStats; } + +private: + + ShHealOper_ModifStats* myModifStats; }; #endif diff --git a/src/GEOMImpl/GEOMImpl_PolylineDumper.cxx b/src/GEOMImpl/GEOMImpl_PolylineDumper.cxx index 05fb9a61a..ba66b5f99 100644 --- a/src/GEOMImpl/GEOMImpl_PolylineDumper.cxx +++ b/src/GEOMImpl/GEOMImpl_PolylineDumper.cxx @@ -152,7 +152,7 @@ void GEOMImpl_PolylineDumper::init() } } - char *aSeparator = "\n\t"; + const char *aSeparator = "\n\t"; Standard_Integer i; std::list >::const_iterator anIt = myCoords.begin(); diff --git a/src/GEOM_I/CMakeLists.txt b/src/GEOM_I/CMakeLists.txt index d916ffe60..24b3731a5 100755 --- a/src/GEOM_I/CMakeLists.txt +++ b/src/GEOM_I/CMakeLists.txt @@ -29,6 +29,7 @@ INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/src/GEOM ${PROJECT_SOURCE_DIR}/src/GEOMAlgo ${PROJECT_SOURCE_DIR}/src/GEOMUtils + ${PROJECT_SOURCE_DIR}/src/ShHealOper ${PROJECT_BINARY_DIR}/idl ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_BINARY_DIR} diff --git a/src/GEOM_I/GEOM_IHealingOperations_i.cc b/src/GEOM_I/GEOM_IHealingOperations_i.cc index cd04c7626..53707cac8 100644 --- a/src/GEOM_I/GEOM_IHealingOperations_i.cc +++ b/src/GEOM_I/GEOM_IHealingOperations_i.cc @@ -27,10 +27,11 @@ #include "GEOM_IHealingOperations_i.hh" #include "GEOM_Engine.hxx" #include "GEOM_Object.hxx" +#include "ShHealOper_ModifStats.hxx" -#include "utilities.h" -#include "OpUtil.hxx" -#include "Utils_ExceptHandlers.hxx" +#include +#include +#include #include #include @@ -439,7 +440,7 @@ GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::DivideEdge (GEOM::GEOM_Object_p GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::DivideEdgeByPoint (GEOM::GEOM_Object_ptr theObject, CORBA::Short theIndex, - GEOM::GEOM_Object_ptr thePoint) + const GEOM::ListOfGO& thePoints) { GEOM::GEOM_Object_var aGEOMObject; @@ -451,14 +452,14 @@ GEOM_IHealingOperations_i::DivideEdgeByPoint (GEOM::GEOM_Object_ptr theObject, if (anObject.IsNull()) return aGEOMObject._retn(); - // Get the point - Handle(GEOM_Object) aPoint = GetObjectImpl(thePoint); - if (aPoint.IsNull()) + // Get the points + std::list< Handle(GEOM_Object) > aPoints; + if (! GetListOfObjectsImpl( thePoints, aPoints )) return aGEOMObject._retn(); // Perform Handle(GEOM_Object) aNewObject = - GetOperations()->DivideEdgeByPoint( anObject, theIndex, aPoint ); + GetOperations()->DivideEdgeByPoint( anObject, theIndex, aPoints ); if (!GetOperations()->IsDone() || aNewObject.IsNull()) return aGEOMObject._retn(); @@ -635,3 +636,26 @@ GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::LimitTolerance (GEOM::GEOM_Obje return GetObject(aNewObject); } + +//================================================================================ +/*! + * \brief Return information on what has been done by the last called healing method + */ +//================================================================================ + +GEOM::ModifStatistics* GEOM_IHealingOperations_i::GetStatistics() +{ + const ShHealOper_ModifStats& stats = * GetOperations()->GetStatistics(); + const std::set< ShHealOper_ModifStats::Datum >& modifs = stats.GetData(); + std::set< ShHealOper_ModifStats::Datum >::const_iterator modif = modifs.begin(); + + GEOM::ModifStatistics_var statsVar = new GEOM::ModifStatistics(); + statsVar->length( modifs.size() ); + for ( int i = 0; modif != modifs.end(); ++modif, ++i ) + { + statsVar[ i ].name = modif->myModif.c_str(); + statsVar[ i ].count = modif->myCount; + } + + return statsVar._retn(); +} diff --git a/src/GEOM_I/GEOM_IHealingOperations_i.hh b/src/GEOM_I/GEOM_IHealingOperations_i.hh index 4d851973d..c1da1d006 100644 --- a/src/GEOM_I/GEOM_IHealingOperations_i.hh +++ b/src/GEOM_I/GEOM_IHealingOperations_i.hh @@ -84,7 +84,7 @@ class GEOM_I_EXPORT GEOM_IHealingOperations_i : GEOM::GEOM_Object_ptr DivideEdgeByPoint (GEOM::GEOM_Object_ptr theObject, CORBA::Short theIndex, - GEOM::GEOM_Object_ptr thePoint); + const GEOM::ListOfGO& thePoints); GEOM::GEOM_Object_ptr FuseCollinearEdgesWithinWire (GEOM::GEOM_Object_ptr theWire, const GEOM::ListOfGO& theVertices); @@ -101,6 +101,8 @@ class GEOM_I_EXPORT GEOM_IHealingOperations_i : ::GEOMImpl_IHealingOperations* GetOperations() { return (::GEOMImpl_IHealingOperations*)GetImpl(); } + GEOM::ModifStatistics* GetStatistics(); + private: Handle(TColStd_HArray1OfInteger) Convert( const GEOM::short_array& ); diff --git a/src/GEOM_SWIG/geomBuilder.py b/src/GEOM_SWIG/geomBuilder.py index 07535cdf9..32d7ca47e 100644 --- a/src/GEOM_SWIG/geomBuilder.py +++ b/src/GEOM_SWIG/geomBuilder.py @@ -6830,12 +6830,12 @@ class geomBuilder(object, GEOM._objref_GEOM_Gen): self._autoPublish(anObj, theName, "divideEdge") return anObj - ## Addition of a point to a given edge of \a theObject by projecting - # another point to the given edge. + ## Addition of points to a given edge of \a theObject by projecting + # other points to the given edge. # @param theObject Shape to be processed. # @param theEdgeIndex Index of edge to be divided within theObject's shape, # if -1, then theObject itself is the edge. - # @param thePoint Point to project to theEdgeIndex-th edge. + # @param thePoints List of points to project to theEdgeIndex-th edge. # @param theName Object name; when specified, this parameter is used # for result publication in the study. Otherwise, if automatic # publication is switched on, default value is used for result name. @@ -6844,16 +6844,16 @@ class geomBuilder(object, GEOM._objref_GEOM_Gen): # # @ref tui_add_point_on_edge "Example" @ManageTransactions("HealOp") - def DivideEdgeByPoint(self, theObject, theEdgeIndex, thePoint, theName=None): + def DivideEdgeByPoint(self, theObject, theEdgeIndex, thePoints, theName=None): """ - Addition of a point to a given edge of \a theObject by projecting - another point to the given edge. + Addition of points to a given edge of \a theObject by projecting + other points to the given edge. Parameters: theObject Shape to be processed. theEdgeIndex The edge or its index to be divided within theObject's shape, if -1, then theObject itself is the edge. - thePoint Point to project to theEdgeIndex-th edge. + thePoints List of points to project to theEdgeIndex-th edge. theName Object name; when specified, this parameter is used for result publication in the study. Otherwise, if automatic publication is switched on, default value is used for result name. @@ -6864,7 +6864,7 @@ class geomBuilder(object, GEOM._objref_GEOM_Gen): # Example: see GEOM_TestHealing.py if isinstance( theEdgeIndex, GEOM._objref_GEOM_Object ): theEdgeIndex = self.GetSubShapeID( theObject, theEdgeIndex ) - anObj = self.HealOp.DivideEdgeByPoint(theObject, theEdgeIndex, thePoint) + anObj = self.HealOp.DivideEdgeByPoint(theObject, theEdgeIndex, ToList( thePoints )) RaiseIfFailed("DivideEdgeByPoint", self.HealOp) self._autoPublish(anObj, theName, "divideEdge") return anObj diff --git a/src/RepairGUI/RepairGUI.cxx b/src/RepairGUI/RepairGUI.cxx index cb0608260..b65327e91 100644 --- a/src/RepairGUI/RepairGUI.cxx +++ b/src/RepairGUI/RepairGUI.cxx @@ -121,3 +121,98 @@ extern "C" return new RepairGUI( parent ); } } + +//===================================================================================== +// Statistics dialog +//===================================================================================== + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + class StatsDlg : public QDialog + { + public: + StatsDlg( GEOM::ModifStatistics_var stats, QWidget* parent ); + }; + + StatsDlg::StatsDlg( GEOM::ModifStatistics_var stats, QWidget* parent ): QDialog( parent ) + { + setModal( false ); + setAttribute( Qt::WA_DeleteOnClose, true ); + setWindowTitle( tr( "GEOM_HEALING_STATS_TITLE" ) ); + setMinimumWidth( 500 ); + + const int nbRows = stats->length(); + const int nbCols = 2; + QTableWidget* table = new QTableWidget( nbRows, nbCols, this ); + table->setEditTriggers( QAbstractItemView::NoEditTriggers ); + table->horizontalHeader()->setResizeMode( 1, QHeaderView::Interactive ); + table->horizontalHeader()->setStretchLastSection( true ); + + QStringList headers; + headers << tr( "GEOM_HEALING_STATS_COL_1" ); + headers << tr( "GEOM_HEALING_STATS_COL_2" ); + table->setHorizontalHeaderLabels( headers ); + + // buttons + + QPushButton* okBtn = new QPushButton( tr( "GEOM_BUT_OK" ), this ); + okBtn->setAutoDefault( true ); + okBtn->setDefault( true ); + okBtn->setFocus(); + // QPushButton* helpBtn = new QPushButton( tr( "GEOM_BUT_HELP" ), this ); + // helpBtn->setAutoDefault( true ); + + QHBoxLayout* btnLayout = new QHBoxLayout; + btnLayout->setMargin( 9 ); + btnLayout->setSpacing( 6 ); + + btnLayout->addWidget( okBtn ); + btnLayout->addStretch( 10 ); + // btnLayout->addWidget( helpBtn ); + + QVBoxLayout* aLay = new QVBoxLayout( this ); + aLay->setMargin( 9 ); + aLay->setSpacing( 6 ); + aLay->addWidget( table ); + aLay->addLayout( btnLayout ); + + // fill the table + for ( int row = 0; row < nbRows; ++row ) + { + table->setItem( row, 0, new QTableWidgetItem( QString::number( stats[ row ].count ))); + table->setItem( row, 1, new QTableWidgetItem( tr( stats[ row ].name.in() ))); + } + + connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() )); + //connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() )); + + } +} + +//================================================================================ +/*! + * \brief Show a dialog providing info on what is done by healing + */ +//================================================================================ + +void RepairGUI::ShowStatistics( GEOM::GEOM_IHealingOperations_var anOper, QWidget* parent ) +{ + GEOM::ModifStatistics_var stats = anOper->GetStatistics(); + + if ( ! &stats.in() || stats->length() == 0 ) + return; + + StatsDlg* dlg = new StatsDlg( stats, parent ); + dlg->exec(); +} diff --git a/src/RepairGUI/RepairGUI.h b/src/RepairGUI/RepairGUI.h index df1eb9c45..26fa5fbbf 100644 --- a/src/RepairGUI/RepairGUI.h +++ b/src/RepairGUI/RepairGUI.h @@ -29,6 +29,9 @@ #include +#include +#include CORBA_CLIENT_HEADER(GEOM_Gen) + //================================================================================= // class : RepairGUI // purpose : @@ -40,6 +43,7 @@ public: ~RepairGUI(); bool OnGUIEvent( int, SUIT_Desktop* ); -}; + static void ShowStatistics( GEOM::GEOM_IHealingOperations_var anOper, QWidget* parent ); +}; #endif // REPAIRGUI_H diff --git a/src/RepairGUI/RepairGUI_ChangeOrientationDlg.cxx b/src/RepairGUI/RepairGUI_ChangeOrientationDlg.cxx index 3d395463b..3d5bbcba9 100644 --- a/src/RepairGUI/RepairGUI_ChangeOrientationDlg.cxx +++ b/src/RepairGUI/RepairGUI_ChangeOrientationDlg.cxx @@ -26,18 +26,19 @@ // #include "RepairGUI_ChangeOrientationDlg.h" -#include -#include -#include +#include "DlgRef.h" +#include "GeometryGUI.h" +#include "GEOMBase.h" +#include "RepairGUI.h" -#include #include -#include #include +#include +#include +#include -#include +#include "GEOMImpl_Types.hxx" -#include //================================================================================= // class : RepairGUI_ChangeOrientationDlg() @@ -280,7 +281,11 @@ bool RepairGUI_ChangeOrientationDlg::execute( ObjectList& objects ) } if ( !anObj->_is_nil() ) + { + if ( !IsPreview() ) + RepairGUI::ShowStatistics( anOper, this ); objects.push_back( anObj._retn() ); + } return true; } diff --git a/src/RepairGUI/RepairGUI_CloseContourDlg.cxx b/src/RepairGUI/RepairGUI_CloseContourDlg.cxx index f57ad4868..77e29a211 100644 --- a/src/RepairGUI/RepairGUI_CloseContourDlg.cxx +++ b/src/RepairGUI/RepairGUI_CloseContourDlg.cxx @@ -26,9 +26,10 @@ // #include "RepairGUI_CloseContourDlg.h" -#include -#include -#include +#include "DlgRef.h" +#include "GeometryGUI.h" +#include "GEOMBase.h" +#include "RepairGUI.h" #include #include @@ -325,8 +326,11 @@ bool RepairGUI_CloseContourDlg::execute (ObjectList& objects) bool aResult = !anObj->_is_nil(); if (aResult) + { + if ( !IsPreview() ) + RepairGUI::ShowStatistics( anOper, this ); objects.push_back(anObj._retn()); - + } return aResult; } diff --git a/src/RepairGUI/RepairGUI_DivideEdgeDlg.cxx b/src/RepairGUI/RepairGUI_DivideEdgeDlg.cxx index 62715108b..ad77079ef 100644 --- a/src/RepairGUI/RepairGUI_DivideEdgeDlg.cxx +++ b/src/RepairGUI/RepairGUI_DivideEdgeDlg.cxx @@ -26,11 +26,12 @@ // #include "RepairGUI_DivideEdgeDlg.h" -#include -#include -#include -#include +#include "DlgRef.h" +#include "GeometryGUI.h" +#include "GEOMBase.h" +#include "RepairGUI.h" +#include #include #include #include @@ -161,7 +162,7 @@ void RepairGUI_DivideEdgeDlg::Init() myEditCurrentArgument = GroupPoints->LineEdit1; myObject = GEOM::GEOM_Object::_nil(); - myPoint.nullify(); + myPoints.clear(); myIndex = -1; myProjectionOK = false; @@ -231,11 +232,8 @@ void RepairGUI_DivideEdgeDlg::displayPreview() BRepBuilderAPI_MakeVertex mkVertex (aPnt); aShape = mkVertex.Shape(); } - else if ( getConstructorId() == BY_POINT_PROJ && myPoint ) + else if ( getConstructorId() == BY_POINT_PROJ && !myPoints.empty() ) { - TopoDS_Shape aPoints; - GEOMBase::GetShape( myPoint.get(), aPoints, TopAbs_SHAPE ); - BRep_Builder builder; TopoDS_Compound compoundOfVV; builder.MakeCompound(compoundOfVV); @@ -245,11 +243,13 @@ void RepairGUI_DivideEdgeDlg::displayPreview() aProjector.Init( aCurve, aFP, aLP ); TopTools_MapOfShape vMap; - TopExp_Explorer vertex( aPoints, TopAbs_VERTEX ); - for ( ; vertex.More(); vertex.Next() ) + for ( int i = 0; i < myPoints.count(); ++i ) { - if ( !vMap.Add( vertex.Current() )) continue; - gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( vertex.Current() )); + TopoDS_Shape aPoint; + GEOMBase::GetShape( myPoints[i].get(), aPoint, TopAbs_VERTEX ); + if ( !vMap.Add( aPoint )) continue; + + gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( aPoint )); aProjector.Perform( p ); if ( aProjector.NbPoints() > 0 ) { @@ -296,13 +296,14 @@ bool RepairGUI_DivideEdgeDlg::ClickOnApply() initName(); - myEditCurrentArgument->setText( "" ); + GroupPoints->LineEdit1->setText( "" ); + GroupPoints->LineEdit2->setText( "" ); myObject = GEOM::GEOM_Object::_nil(); - myPoint.nullify(); + myPoints.clear(); myIndex = -1; myProjectionOK = false; - ConstructorsClicked(getConstructorId()); + GroupPoints->PushButton1->click(); return true; } @@ -322,10 +323,11 @@ void RepairGUI_DivideEdgeDlg::SelectionIntoArgument() { myObject = GEOM::GEOM_Object::_nil(); myIndex = -1; + myProjectionOK = false; } else //if ( myEditCurrentArgument == GroupPoints->LineEdit2 ) { - myPoint.nullify(); + myPoints.clear(); myProjectionOK = false; } @@ -333,7 +335,7 @@ void RepairGUI_DivideEdgeDlg::SelectionIntoArgument() SALOME_ListIO aSelList; aSelMgr->selectedObjects(aSelList); - if ( aSelList.Extent() == 1 ) { + if ( toSelectObject && aSelList.Extent() == 1 ) { Handle(SALOME_InteractiveObject) anIO = aSelList.First(); GEOM::GEOM_Object_var aSelectedObj = GEOMBase::ConvertIOinGEOMObject( anIO ); if ( !CORBA::is_nil( aSelectedObj ) ) @@ -343,7 +345,7 @@ void RepairGUI_DivideEdgeDlg::SelectionIntoArgument() if ( GEOMBase::GetShape( aSelectedObj, aShape, TopAbs_SHAPE ) ) { const int aType = aShape.ShapeType(); - if ( aType <= TopAbs_EDGE || !toSelectObject ) // edge, wire, face, shell, solid, compound + if ( aType <= TopAbs_EDGE ) // edge, wire, face, shell, solid, compound { GEOM::short_array anIndexes; @@ -354,34 +356,35 @@ void RepairGUI_DivideEdgeDlg::SelectionIntoArgument() if ( !aMap.IsEmpty() ) // sub-shape selection { - if ( toSelectObject ) { - myIndex = aMap( 1 ); - myObject = aSelectedObj; - myEditCurrentArgument->setText( aName += QString( ":edge_%1" ).arg( myIndex ) ); - } - else if (( myPoint = getSelected( TopAbs_VERTEX ))) - { - myEditCurrentArgument->setText( aName += QString( ":vertex_%1" ).arg( aMap( 1 ))); - } + myIndex = aMap( 1 ); + myObject = aSelectedObj; + myEditCurrentArgument->setText( aName += QString( ":edge_%1" ).arg( myIndex ) ); } - else if ( aType == TopAbs_EDGE && toSelectObject ) // single shape selection + else if ( aType == TopAbs_EDGE ) // single shape selection { myIndex = -1; myObject = aSelectedObj; - myEditCurrentArgument->setText( aName ); - } - else if ( aType == TopAbs_VERTEX && !toSelectObject ) // single shape selection - { - myPoint = aSelectedObj; - myEditCurrentArgument->setText( aName ); + myEditCurrentArgument->setText( GEOMBase::GetName( myObject ) ); } else // face, shell, solid or compound was selected, and NOT its sub-shape. { + myIndex = -1; + myObject = GEOM::GEOM_Object::_nil(); } } } } } + if ( !toSelectObject ) + { + myPoints = getSelected( TopAbs_VERTEX, -1, /*strict=*/true ); + if ( myPoints.empty() ) + myEditCurrentArgument->setText( "" ); + else if ( myPoints.count() == 1 ) + myEditCurrentArgument->setText( GEOMBase::GetName( myPoints[0].get() )); + else + myEditCurrentArgument->setText( QObject::tr( "%1_vertices" ).arg( myPoints.count() )); + } displayPreview(); } @@ -487,7 +490,7 @@ bool RepairGUI_DivideEdgeDlg::isValid( QString& msg ) } else if ( getConstructorId() == BY_POINT_PROJ ) { - if (( ok = myPoint ) && !( ok = myProjectionOK )) + if (( ok = myPoints.count() ) && !( ok = myProjectionOK )) msg = tr("DEVIDE_EDGE_BAD_PROJ_MSG"); } return !myObject->_is_nil() && ok; @@ -502,10 +505,17 @@ bool RepairGUI_DivideEdgeDlg::execute( ObjectList& objects ) GEOM::GEOM_IHealingOperations_var anOper = GEOM::GEOM_IHealingOperations::_narrow( getOperation() ); GEOM::GEOM_Object_var anObj; if ( getConstructorId() == BY_PARAM ) + { anObj = anOper->DivideEdge( myObject, myIndex, myValEdt->value(), getIsByParameter() ); + } else - anObj = anOper->DivideEdgeByPoint( myObject, myIndex, myPoint.get() ); - + { + GEOM::ListOfGO_var objList = new GEOM::ListOfGO; + objList->length( myPoints.count() ); + for ( int i = 0; i < myPoints.count(); ++i ) + objList[i] = myPoints[i].copy(); + anObj = anOper->DivideEdgeByPoint( myObject, myIndex, objList ); + } bool aResult = !anObj->_is_nil(); if ( aResult ) { @@ -517,6 +527,8 @@ bool RepairGUI_DivideEdgeDlg::execute( ObjectList& objects ) aParameters << ""; anObj->SetParameters(aParameters.join(":").toLatin1().constData()); } + if ( !IsPreview() ) + RepairGUI::ShowStatistics( anOper, this ); objects.push_back( anObj._retn() ); } @@ -552,5 +564,6 @@ void RepairGUI_DivideEdgeDlg::initSelection() //================================================================================= void RepairGUI_DivideEdgeDlg::addSubshapesToStudy() { - GEOMBase::PublishSubObject( myPoint.get() ); + for ( int i = 0; i < myPoints.count(); ++i ) + GEOMBase::PublishSubObject( myPoints[i].get() ); } diff --git a/src/RepairGUI/RepairGUI_DivideEdgeDlg.h b/src/RepairGUI/RepairGUI_DivideEdgeDlg.h index 129c9895c..88cf5229d 100644 --- a/src/RepairGUI/RepairGUI_DivideEdgeDlg.h +++ b/src/RepairGUI/RepairGUI_DivideEdgeDlg.h @@ -62,7 +62,7 @@ private: private: GEOM::GEOM_Object_var myObject; - GEOM::GeomObjPtr myPoint; + QList myPoints; bool myProjectionOK; DlgRef_2SelExt* GroupPoints; diff --git a/src/RepairGUI/RepairGUI_LimitToleranceDlg.cxx b/src/RepairGUI/RepairGUI_LimitToleranceDlg.cxx index 69b37b9f6..0b447d106 100644 --- a/src/RepairGUI/RepairGUI_LimitToleranceDlg.cxx +++ b/src/RepairGUI/RepairGUI_LimitToleranceDlg.cxx @@ -23,11 +23,12 @@ #include "RepairGUI_LimitToleranceDlg.h" -#include -#include -#include -#include +#include "DlgRef.h" +#include "GeometryGUI.h" +#include "GEOMBase.h" +#include "RepairGUI.h" +#include #include #include #include @@ -303,6 +304,8 @@ bool RepairGUI_LimitToleranceDlg::execute(ObjectList& objects) QStringList aParameters; aParameters << myTolEdt->text(); anObj->SetParameters(aParameters.join(":").toLatin1().constData()); + if ( !IsPreview() ) + RepairGUI::ShowStatistics( anOper, this ); objects.push_back(anObj._retn()); } diff --git a/src/RepairGUI/RepairGUI_RemoveHolesDlg.cxx b/src/RepairGUI/RepairGUI_RemoveHolesDlg.cxx index 56b5aa004..92a3b0c76 100644 --- a/src/RepairGUI/RepairGUI_RemoveHolesDlg.cxx +++ b/src/RepairGUI/RepairGUI_RemoveHolesDlg.cxx @@ -26,9 +26,10 @@ // #include "RepairGUI_RemoveHolesDlg.h" -#include -#include -#include +#include "DlgRef.h" +#include "GeometryGUI.h" +#include "GEOMBase.h" +#include "RepairGUI.h" #include #include @@ -353,7 +354,11 @@ bool RepairGUI_RemoveHolesDlg::execute (ObjectList& objects) GEOM::GEOM_Object_var anObj = anOper->FillHoles(myObject, myWiresInd); aResult = !anObj->_is_nil(); if (aResult) + { + if ( !IsPreview() ) + RepairGUI::ShowStatistics( anOper, this ); objects.push_back(anObj._retn()); + } } return aResult; diff --git a/src/RepairGUI/RepairGUI_RemoveIntWiresDlg.cxx b/src/RepairGUI/RepairGUI_RemoveIntWiresDlg.cxx index 927656c57..a60e6ed72 100644 --- a/src/RepairGUI/RepairGUI_RemoveIntWiresDlg.cxx +++ b/src/RepairGUI/RepairGUI_RemoveIntWiresDlg.cxx @@ -26,9 +26,10 @@ // #include "RepairGUI_RemoveIntWiresDlg.h" -#include -#include -#include +#include "DlgRef.h" +#include "GeometryGUI.h" +#include "GEOMBase.h" +#include "RepairGUI.h" #include #include @@ -312,8 +313,11 @@ bool RepairGUI_RemoveIntWiresDlg::execute (ObjectList& objects) bool aResult = !anObj->_is_nil(); if (aResult) + { + if ( !IsPreview() ) + RepairGUI::ShowStatistics( anOper, this ); objects.push_back(anObj._retn()); - + } return aResult; } diff --git a/src/RepairGUI/RepairGUI_ShapeProcessDlg.cxx b/src/RepairGUI/RepairGUI_ShapeProcessDlg.cxx index 926f1eb80..e05f008d3 100755 --- a/src/RepairGUI/RepairGUI_ShapeProcessDlg.cxx +++ b/src/RepairGUI/RepairGUI_ShapeProcessDlg.cxx @@ -26,10 +26,11 @@ #include "RepairGUI_ShapeProcessDlg.h" -#include -#include -#include -#include +#include "DlgRef.h" +#include "GeometryGUI.h" +#include "GEOMBase.h" +#include "GEOMImpl_Types.hxx" +#include "RepairGUI.h" #include #include @@ -652,6 +653,8 @@ bool RepairGUI_ShapeProcessDlg::execute( ObjectList& objects ) aParameters << getTexts( aParams ); anObj->SetParameters(aParameters.join(":").toLatin1().constData()); + + RepairGUI::ShowStatistics( anOper, this ); } objects.push_back( anObj._retn() ); } diff --git a/src/RepairGUI/RepairGUI_SuppressFacesDlg.cxx b/src/RepairGUI/RepairGUI_SuppressFacesDlg.cxx index 43a0f629e..d7c297168 100644 --- a/src/RepairGUI/RepairGUI_SuppressFacesDlg.cxx +++ b/src/RepairGUI/RepairGUI_SuppressFacesDlg.cxx @@ -24,9 +24,10 @@ #include "RepairGUI_SuppressFacesDlg.h" -#include -#include -#include +#include "DlgRef.h" +#include "GeometryGUI.h" +#include "GEOMBase.h" +#include "RepairGUI.h" #include #include @@ -376,8 +377,11 @@ bool RepairGUI_SuppressFacesDlg::execute (ObjectList& objects) bool aResult = !anObj->_is_nil(); if (aResult) + { + if ( !IsPreview() ) + RepairGUI::ShowStatistics( anOper, this ); objects.push_back(anObj._retn()); - + } return aResult; } diff --git a/src/ShHealOper/CMakeLists.txt b/src/ShHealOper/CMakeLists.txt index 8d2d3a2ba..9def66279 100755 --- a/src/ShHealOper/CMakeLists.txt +++ b/src/ShHealOper/CMakeLists.txt @@ -52,6 +52,7 @@ SET(ShHealOper_HEADERS ShHealOper_SplitCurve3d.hxx ShHealOper_ChangeOrientation.hxx ShHealOper_Tool.hxx + ShHealOper_ModifStats.hxx ) # --- sources --- diff --git a/src/ShHealOper/ShHealOper_ChangeOrientation.cxx b/src/ShHealOper/ShHealOper_ChangeOrientation.cxx index e48ba58d5..04112efa7 100644 --- a/src/ShHealOper/ShHealOper_ChangeOrientation.cxx +++ b/src/ShHealOper/ShHealOper_ChangeOrientation.cxx @@ -73,6 +73,7 @@ Standard_Boolean ShHealOper_ChangeOrientation::Perform() while (itr.More()) { B.Add(myResultShape,itr.Value().Reversed()); itr.Next(); + myStatistics.AddModif("Face reversed"); } } else if (myInitShape.ShapeType() == TopAbs_FACE) @@ -82,6 +83,7 @@ Standard_Boolean ShHealOper_ChangeOrientation::Perform() while (itr.More()) { B.Add(myResultShape,itr.Value()); itr.Next(); + myStatistics.AddModif("Wire reversed"); } myResultShape.Reverse(); } @@ -105,12 +107,14 @@ Standard_Boolean ShHealOper_ChangeOrientation::Perform() if ( myInitShape.ShapeType() == TopAbs_EDGE ) { myResultShape = reversedEdges.First(); + myStatistics.AddModif("Edge reversed"); } else { BRepBuilderAPI_MakeWire wire; wire.Add( reversedEdges ); myResultShape = wire; + myStatistics.AddModif("Wire reversed"); } // myResultShape = myInitShape.EmptyCopied(); // TopoDS_Iterator itr (myInitShape); @@ -132,6 +136,13 @@ Standard_Boolean ShHealOper_ChangeOrientation::Perform() myResultShape.Orientation(TopAbs_REVERSED); else myResultShape.Orientation(TopAbs_FORWARD); + + switch( myResultShape.ShapeType() ) { + case TopAbs_SOLID : myStatistics.AddModif("Solid reversed"); break; + case TopAbs_COMPSOLID: myStatistics.AddModif("Compsolid reversed"); break; + case TopAbs_COMPOUND : myStatistics.AddModif("Compound reversed"); break; + default:; + } } return true; diff --git a/src/ShHealOper/ShHealOper_CloseContour.cxx b/src/ShHealOper/ShHealOper_CloseContour.cxx index 67c69b50e..0e9dfaa45 100644 --- a/src/ShHealOper/ShHealOper_CloseContour.cxx +++ b/src/ShHealOper/ShHealOper_CloseContour.cxx @@ -252,10 +252,14 @@ Standard_Boolean ShHealOper_CloseContour::fixGaps(const Handle(ShapeExtend_WireD Standard_Integer ind1 = (ind2 >1 ? ind2 -1 : theWire->NbEdges()); TopoDS_Edge aE1= theWire->Edge(ind1); TopoDS_Edge aE2= theWire->Edge(ind2); - if(!myModeVertex) + if(!myModeVertex) { buildEdge(aE1,aE2,theCommonFaces); - else + myStatistics.AddModif("An edge added to close a wire"); + } + else { myMaxTolerance = RealLast(); + myStatistics.AddModif("Tolerance of vertex increased to close a wire"); + } if(ind2 == ind1) break; } } @@ -268,8 +272,9 @@ Standard_Boolean ShHealOper_CloseContour::fixGaps(const Handle(ShapeExtend_WireD //function : checkOneFace //purpose : //======================================================================= -Standard_Boolean ShHealOper_CloseContour::checkOneFace(const Handle(ShapeExtend_WireData)& theSewd, - TopTools_SequenceOfShape& theCommonFaces) const +Standard_Boolean +ShHealOper_CloseContour::checkOneFace(const Handle(ShapeExtend_WireData)& theSewd, + TopTools_SequenceOfShape& theCommonFaces) const { TopTools_IndexedMapOfShape amapfaces; TopoDS_Edge aEdge1 = theSewd->Edge(1); diff --git a/src/ShHealOper/ShHealOper_EdgeDivide.cxx b/src/ShHealOper/ShHealOper_EdgeDivide.cxx index 99de5efe5..d188ab144 100644 --- a/src/ShHealOper/ShHealOper_EdgeDivide.cxx +++ b/src/ShHealOper/ShHealOper_EdgeDivide.cxx @@ -142,6 +142,7 @@ Standard_Boolean ShHealOper_EdgeDivide::Perform(const TopoDS_Shape& theEdge, TopTools_MapOfShape vMap; TopExp_Explorer vertex( thePoints, TopAbs_VERTEX ); + std::set< double > params; // to exclude equal params for ( ; vertex.More(); vertex.Next() ) { if ( !vMap.Add( vertex.Current() )) continue; @@ -151,9 +152,24 @@ Standard_Boolean ShHealOper_EdgeDivide::Perform(const TopoDS_Shape& theEdge, { double u = double( aProjector.LowerDistanceParameter() ); double param = ( u - aFirst ) / ( aLast - aFirst ); - aSeqValues->Append( param ); + params.insert( param ); } } + // remove too close params + params.insert( 0 ); + params.insert( 1 ); + std::set< double >::iterator p2 = params.begin(), p1 = p2++; + while ( p2 != params.end() ) + { + if ( Abs( *p2 - *p1 ) < 1e-3 ) // compare normalized params + params.erase( p1 ); + p1 = p2++; + } + p1 = params.begin(); ++p1; // skip aFirst + p2 = params.end(); --p2; // skip aLast + for ( ; p1 != p2; ++p1 ) + aSeqValues->Append( *p1 ); + myDone = build(aSeqValues); return myDone; } @@ -219,7 +235,10 @@ Standard_Boolean ShHealOper_EdgeDivide::build(const Handle(TColStd_HSequenceOfRe myErrorStatus = ShHealOper_ErrorExecution; } if(isDone) + { myResultShape = myContext->Apply(myInitShape); + myStatistics.AddModif("Vertex added on edge", theValues->Length() ); + } return isDone; } diff --git a/src/ShHealOper/ShHealOper_FillHoles.cxx b/src/ShHealOper/ShHealOper_FillHoles.cxx index 114326a8b..82f78cc27 100644 --- a/src/ShHealOper/ShHealOper_FillHoles.cxx +++ b/src/ShHealOper/ShHealOper_FillHoles.cxx @@ -186,7 +186,10 @@ Standard_Boolean ShHealOper_FillHoles::Fill(const TopTools_SequenceOfShape& theF myDone = (addFace(aSurf,aWire,aCurves2d,aOrders,aSenses) || myDone); } if(myDone) + { myResultShape = myContext->Apply(myResultShape); + myStatistics.AddModif( "Face created to fill hole" , aSeqWires->Length() ); + } return myDone; } diff --git a/src/ShHealOper/ShHealOper_ModifStats.hxx b/src/ShHealOper/ShHealOper_ModifStats.hxx new file mode 100644 index 000000000..ad043b8a7 --- /dev/null +++ b/src/ShHealOper/ShHealOper_ModifStats.hxx @@ -0,0 +1,78 @@ +// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, 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 +// + +// File : ShHealOper_ModifStats.hxx +// Created : Mon Dec 1 15:29:48 2014 + +#ifndef __ShHealOper_ModifStats_HXX__ +#define __ShHealOper_ModifStats_HXX__ + +#include +#include + +/*! + * \brief Structure describing modifications done in a shape + */ +class Standard_EXPORT ShHealOper_ModifStats +{ + public: + + struct Standard_EXPORT Datum + { + std::string myModif; // what is done + mutable int myCount; // how many times (in how many sub-shapes) + + Datum( const std::string& txt, int cnt=0 ): myModif( txt ), myCount(cnt) {} + bool operator< ( const Datum& o ) const { return myModif < o.myModif; } + }; + + // record a modification + void AddModif( const std::string& modifText, int nb=1 ) + { + std::set< Datum >::iterator d = myData.insert( Datum( modifText )).first; + d->myCount += nb; + } + + // add data from another ShHealOper_ModifStats + void Add( const ShHealOper_ModifStats& stats ) + { + if ( myData.empty() ) myData = stats.myData; + else { + std::set< Datum >::const_iterator d = stats.myData.begin(); + for ( ; d != stats.myData.end(); ++d ) + AddModif( d->myModif, d->myCount ); + } + } + + // return all recorder modifications + const std::set< Datum >& GetData() const { return myData; } + + // clear all statistics + void Clear() { myData.clear(); } + + protected: + + std::set< Datum > myData; + +}; + +#endif diff --git a/src/ShHealOper/ShHealOper_RemoveInternalWires.cxx b/src/ShHealOper/ShHealOper_RemoveInternalWires.cxx index 698cedaf9..f50da898d 100644 --- a/src/ShHealOper/ShHealOper_RemoveInternalWires.cxx +++ b/src/ShHealOper/ShHealOper_RemoveInternalWires.cxx @@ -137,6 +137,9 @@ Standard_Boolean ShHealOper_RemoveInternalWires::removeWire(const TopoDS_Face& t } } } + if ( isremove ) + myStatistics.AddModif( "Wire removed" ); + return isremove; } //======================================================================= diff --git a/src/ShHealOper/ShHealOper_ShapeProcess.cxx b/src/ShHealOper/ShHealOper_ShapeProcess.cxx index fa516e924..d991e1f7e 100644 --- a/src/ShHealOper/ShHealOper_ShapeProcess.cxx +++ b/src/ShHealOper/ShHealOper_ShapeProcess.cxx @@ -39,6 +39,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include //======================================================================= //function : ShHealOper_ShapeProcess() @@ -52,8 +59,10 @@ ShHealOper_ShapeProcess::ShHealOper_ShapeProcess ( ) : //myResource = new Resource_Manager("ShHealing"); myPrefix = "ShapeProcess"; mySaveHistoryMode = Standard_False; - myLevel = TopAbs_FACE; + myLevel = TopAbs_EDGE; myDone = Standard_False; + myOperations.Context()->SetDetalisation ( TopAbs_EDGE ); + myOperations.Context()->SetTraceLevel( 3 ); } //======================================================================= @@ -63,23 +72,22 @@ ShHealOper_ShapeProcess::ShHealOper_ShapeProcess ( ) : ShHealOper_ShapeProcess::ShHealOper_ShapeProcess (const TCollection_AsciiString& theNameResource, const TCollection_AsciiString& thePrefix ) : - myOperations(theNameResource.ToCString(),thePrefix.ToCString()) + myOperations(theNameResource.ToCString(),thePrefix.ToCString()) { //myResource = new Resource_Manager(theNameResource); myPrefix = thePrefix; mySaveHistoryMode = Standard_False; - myLevel = TopAbs_FACE; + myLevel = TopAbs_EDGE; myDone = Standard_False; } //======================================================================= //function : Perform -//purpose : +//purpose : //======================================================================= -void ShHealOper_ShapeProcess::Perform(const TopoDS_Shape& theOldShape, - TopoDS_Shape& theNewShape) +void ShHealOper_ShapeProcess::Perform(const TopoDS_Shape& theOldShape, + TopoDS_Shape& theNewShape) { - myMapModifications.Clear(); //ShapeProcessAPI_ApplySequence aOperations(myResource,myPrefix.ToCString()); //myDone = Standard_False; @@ -99,12 +107,50 @@ void ShHealOper_ShapeProcess::Perform(const TopoDS_Shape& theOldShape, myDone = !anOldShape.IsSame(theNewShape); if(!myDone) { Standard_Real aendTol =aSatol.Tolerance(theNewShape,0); - myDone = (fabs(ainitTol - aendTol) > Precision::Confusion()); + myDone = (fabs(ainitTol - aendTol) > Precision::Confusion()); + if ( myDone ) { + if ( ainitTol > aendTol ) + myStatistics.AddModif( "Tolerance fixed (decreased)" ); + else + myStatistics.AddModif( "Tolerance fixed (increased)" ); + } } + + // fill myStatistics with messages + Handle(ShapeExtend_MsgRegistrator) msg = myOperations.Context()->Messages(); + const ShapeExtend_DataMapOfShapeListOfMsg& shape2msg = msg->MapShape(); + ShapeExtend_DataMapIteratorOfDataMapOfShapeListOfMsg s2msg( shape2msg ); + for ( ; s2msg.More(); s2msg.Next() ) + { + const Message_ListOfMsg & msgList = s2msg.Value(); + Message_ListIteratorOfListOfMsg mIt( msgList ); + for ( ; mIt.More(); mIt.Next() ) + { + Message_Msg& m = mIt.Value(); + TCollection_AsciiString txt = m.Get(); + myStatistics.AddModif( txt.ToCString() ); + } + } + +// for (TopTools_DataMapIteratorOfDataMapOfShapeShape It (myOperations.Context()->Map()); It.More(); It.Next()) { +// TopoDS_Shape keyshape = It.Key(), valueshape = It.Value(); +// /* if (keyshape.ShapeType() == TopAbs_SHELL) { +// if (valueshape.IsNull()) SN++; +// else SS++; +// } +// else if (keyshape.ShapeType() == TopAbs_FACE)*/ { +// if (valueshape.IsNull()) cout << "Removed" << endl; +// else { +// TopAbs::Print( keyshape.ShapeType(), cout ) << " -> "; +// TopAbs::Print( valueshape.ShapeType(), cout ) << " IsSame()=" << keyshape.IsSame(valueshape) << endl; +// } +// } +// } + } //======================================================================= //function : SetOperators -//purpose : +//purpose : //======================================================================= void ShHealOper_ShapeProcess::SetOperators(const TColStd_SequenceOfAsciiString& theSeqOperators) @@ -127,8 +173,8 @@ void ShHealOper_ShapeProcess::SetOperators(const TColStd_SequenceOfAsciiString& //purpose : //======================================================================= -void ShHealOper_ShapeProcess::SetParameter(const TCollection_AsciiString& theNameParam, - const TCollection_AsciiString& theVal) +void ShHealOper_ShapeProcess::SetParameter(const TCollection_AsciiString& theNameParam, + const TCollection_AsciiString& theVal) { TCollection_AsciiString anameParam(myPrefix); anameParam += "."; @@ -171,14 +217,14 @@ Standard_Boolean ShHealOper_ShapeProcess::GetOperators(TColStd_SequenceOfAsciiSt //======================================================================= Standard_Boolean ShHealOper_ShapeProcess::GetParameter(const TCollection_AsciiString& theNameParam, - TCollection_AsciiString& theVal) + TCollection_AsciiString& theVal) { TCollection_AsciiString namePar(myPrefix); namePar += "."; namePar += theNameParam; if(!myOperations.Context()->ResourceManager()->Find(namePar.ToCString())) return Standard_False; - + theVal = myOperations.Context()->ResourceManager()->Value(namePar.ToCString()); return Standard_True; } diff --git a/src/ShHealOper/ShHealOper_ShapeProcess.hxx b/src/ShHealOper/ShHealOper_ShapeProcess.hxx index f83f6e10e..67616a5fd 100644 --- a/src/ShHealOper/ShHealOper_ShapeProcess.hxx +++ b/src/ShHealOper/ShHealOper_ShapeProcess.hxx @@ -35,10 +35,12 @@ #include #include +#include "ShHealOper_Tool.hxx" + /// Class ShHealOper_ShapeProcess //Class for performing Shape healing operations on the shape. -class ShHealOper_ShapeProcess +class ShHealOper_ShapeProcess : public ShHealOper_Tool { public: // ---------- PUBLIC METHODS ---------- diff --git a/src/ShHealOper/ShHealOper_Tool.cxx b/src/ShHealOper/ShHealOper_Tool.cxx index 6fb613346..35a7924d4 100644 --- a/src/ShHealOper/ShHealOper_Tool.cxx +++ b/src/ShHealOper/ShHealOper_Tool.cxx @@ -59,4 +59,5 @@ void ShHealOper_Tool::Init(const TopoDS_Shape& theShape) myErrorStatus =ShHealOper_NotError; myInitShape = theShape; myContext->Apply(myInitShape); + myStatistics.Clear(); } diff --git a/src/ShHealOper/ShHealOper_Tool.hxx b/src/ShHealOper/ShHealOper_Tool.hxx index a8bec37bd..a06c5885a 100644 --- a/src/ShHealOper/ShHealOper_Tool.hxx +++ b/src/ShHealOper/ShHealOper_Tool.hxx @@ -27,10 +27,11 @@ #ifndef ShHealOper_Tool_HeaderFile #define ShHealOper_Tool_HeaderFile -#include #include #include +#include "ShHealOper_ModifStats.hxx" + /// Class ShHealOper_Tool // //enumeration for definition of the status of the error if operation failed @@ -69,12 +70,12 @@ class ShHealOper_Tool } //Returns modified shape obtained after operation from initial shape. - inline Standard_Boolean IsDone() const + inline Standard_Boolean IsDone() const { return myDone; } //Returns status of the operation. - + inline void SetContext(Handle(ShapeBuild_ReShape)& theContext) { myContext = theContext; @@ -91,17 +92,31 @@ class ShHealOper_Tool { return myErrorStatus; } - protected: + + ShHealOper_ModifStats& GetStatistics() + { + return myStatistics; + } + + const ShHealOper_ModifStats& GetStatistics() const + { + return myStatistics; + } + // Returns statistics of what is done + +protected: // ---------- PROTECTED FIELDS ---------- Handle(ShapeBuild_ReShape) myContext; - TopoDS_Shape myInitShape; - TopoDS_Shape myResultShape; - Standard_Boolean myDone; - ShHealOper_Error myErrorStatus; - public: -// Declaration of CASCADE RTTI -//DEFINE_STANDARD_RTTI (ShHealOper_Tool) + TopoDS_Shape myInitShape; + TopoDS_Shape myResultShape; + Standard_Boolean myDone; + ShHealOper_Error myErrorStatus; + ShHealOper_ModifStats myStatistics; + +public: + // Declaration of CASCADE RTTI + //DEFINE_STANDARD_RTTI (ShHealOper_Tool) }; // Definition of HANDLE object using Standard_DefineHandle.hxx -- 2.39.2