diff --git a/src/BOPAlgo/BOPAlgo_RemoveFeatures.cxx b/src/BOPAlgo/BOPAlgo_RemoveFeatures.cxx index 7616e1d841..12b972b3a1 100644 --- a/src/BOPAlgo/BOPAlgo_RemoveFeatures.cxx +++ b/src/BOPAlgo/BOPAlgo_RemoveFeatures.cxx @@ -119,12 +119,41 @@ static void FindSolid(const TopoDS_Shape& theSolIn, BOPAlgo_Builder& theBuilder, TopoDS_Shape& theSolOut); +namespace +{ + //======================================================================= + //function : BOPAlgo_PIOperation + //purpose : List of operations to be supported by the Progress Indicator + //======================================================================= + enum BOPAlgo_PIOperation + { + PIOperation_PrepareFeatures = 0, + PIOperation_RemoveFeatures, + PIOperation_UpdateHistory, + PIOperation_SimplifyResult, + + PIOperation_Last + }; +} + +//======================================================================= +// function: fillPISteps +// purpose: +//======================================================================= +void BOPAlgo_RemoveFeatures::fillPIConstants (const Standard_Real theWhole, + BOPAlgo_PISteps& theSteps) const +{ + theSteps.SetStep(PIOperation_PrepareFeatures, 0.05 * theWhole); + theSteps.SetStep(PIOperation_RemoveFeatures, 0.8 * theWhole); + theSteps.SetStep(PIOperation_UpdateHistory, 0.05 * theWhole); + theSteps.SetStep(PIOperation_SimplifyResult, 0.1 * theWhole); +} //======================================================================= // function: Perform // purpose: Performs the removal of the requested faces from the input shape //======================================================================= -void BOPAlgo_RemoveFeatures::Perform(const Message_ProgressRange& /*theRange*/) +void BOPAlgo_RemoveFeatures::Perform(const Message_ProgressRange& theRange) { try { @@ -137,21 +166,36 @@ void BOPAlgo_RemoveFeatures::Perform(const Message_ProgressRange& /*theRange*/) CheckData(); if (HasErrors()) return; + Message_ProgressScope aPS(theRange, "Removing features", 100); + BOPAlgo_PISteps aSteps(PIOperation_Last); + analyzeProgress(100., aSteps); // Prepare the faces to remove. - PrepareFeatures(); + PrepareFeatures(aPS.Next(aSteps.GetStep(PIOperation_PrepareFeatures))); if (HasErrors()) + { return; + } // Remove the features and fill the created gaps - RemoveFeatures(); + RemoveFeatures(aPS.Next(aSteps.GetStep(PIOperation_RemoveFeatures))); + if (HasErrors()) + { + return; + } // Update history with the removed features - UpdateHistory(); - + UpdateHistory(aPS.Next(aSteps.GetStep(PIOperation_UpdateHistory))); + if (HasErrors()) + { + return; + } // Simplify the result - SimplifyResult(); - + SimplifyResult(aPS.Next(aSteps.GetStep(PIOperation_SimplifyResult))); + if (HasErrors()) + { + return; + } // Post treatment PostTreat(); } @@ -243,7 +287,7 @@ void BOPAlgo_RemoveFeatures::CheckData() // function: PrepareFeatures // purpose: Prepares the features to remove //======================================================================= -void BOPAlgo_RemoveFeatures::PrepareFeatures() +void BOPAlgo_RemoveFeatures::PrepareFeatures(const Message_ProgressRange& theRange) { // Map all sub-shapes of the input solids TopExp::MapShapes(myInputShape, myInputsMap); @@ -251,12 +295,18 @@ void BOPAlgo_RemoveFeatures::PrepareFeatures() // Collect all faces of the input shape requested for removal TopTools_ListOfShape aFacesToRemove; TopTools_ListIteratorOfListOfShape aIt(myFacesToRemove); - for (; aIt.More(); aIt.Next()) + Message_ProgressScope aPSOuter(theRange, "Preparing features", 2); + Message_ProgressScope aPS(aPSOuter.Next(), "Preparing the faces to remove", myFacesToRemove.Size()); + for (; aIt.More(); aIt.Next(),aPS.Next()) { const TopoDS_Shape& aS = aIt.Value(); TopExp_Explorer anExpF(aS, TopAbs_FACE); for (; anExpF.More(); anExpF.Next()) { + if (UserBreak(aPS)) + { + return; + } const TopoDS_Shape& aF = anExpF.Current(); if (myInputsMap.Contains(aF)) aFacesToRemove.Append(aF); @@ -327,6 +377,11 @@ public: //! @name Setters/Getters return myHistory; } + void SetRange(const Message_ProgressRange& theRange) + { + myRange = theRange; + } + public: //! @name Perform the operation //! Performs the extension of the adjacent faces and @@ -337,11 +392,17 @@ public: //! @name Perform the operation try { + Message_ProgressScope aPS(myRange, NULL, 3); + myHistory = new BRepTools_History(); // Find the faces adjacent to the faces of the feature TopTools_IndexedMapOfShape aMFAdjacent; - FindAdjacentFaces(aMFAdjacent); + FindAdjacentFaces(aMFAdjacent, aPS.Next()); + if (!aPS.More()) + { + return; + } myHasAdjacentFaces = (aMFAdjacent.Extent() > 0); if (!myHasAdjacentFaces) @@ -349,10 +410,14 @@ public: //! @name Perform the operation // Extend the adjacent faces keeping the connection to the original faces TopTools_IndexedDataMapOfShapeShape aFaceExtFaceMap; - ExtendAdjacentFaces(aMFAdjacent, aFaceExtFaceMap); + ExtendAdjacentFaces(aMFAdjacent, aFaceExtFaceMap, aPS.Next()); + if (!aPS.More()) + { + return; + } // Trim the extended faces - TrimExtendedFaces(aFaceExtFaceMap); + TrimExtendedFaces(aFaceExtFaceMap, aPS.Next()); } catch (Standard_Failure const&) { @@ -380,17 +445,22 @@ public: //! @name Obtain the result private: //! @name Private methods performing the operation //! Finds the faces adjacent to the feature and stores them into outgoing map. - void FindAdjacentFaces(TopTools_IndexedMapOfShape& theMFAdjacent) + void FindAdjacentFaces(TopTools_IndexedMapOfShape& theMFAdjacent, const Message_ProgressRange& theRange) { // Map the faces of the feature to avoid them in the map of adjacent faces TopoDS_Iterator aIt(myFeature); for (; aIt.More(); aIt.Next()) myFeatureFacesMap.Add(aIt.Value()); - + Message_ProgressScope aPSOuter(theRange, NULL, 2); // Find faces adjacent to the feature using the connection map aIt.Initialize(myFeature); - for (; aIt.More(); aIt.Next()) + Message_ProgressScope aPSF(aPSOuter.Next(), "Looking for adjacent faces", 1, Standard_True); + for (; aIt.More(); aIt.Next(), aPSF.Next()) { + if (!aPSF.More()) + { + return; + } const TopoDS_Shape& aF = aIt.Value(); TopExp_Explorer anExpE(aF, TopAbs_EDGE); for (; anExpE.More(); anExpE.Next()) @@ -420,8 +490,13 @@ private: //! @name Private methods performing the operation // Find solids containing the edges of adjacent faces const Standard_Integer aNbFA = theMFAdjacent.Extent(); - for (Standard_Integer i = 1; i <= aNbFA; ++i) + Message_ProgressScope aPSS(aPSOuter.Next(), "Looking for adjacent solids", aNbFA); + for (Standard_Integer i = 1; i <= aNbFA; ++i, aPSS.Next()) { + if (!aPSS.More()) + { + return; + } TopExp_Explorer anExpEA(theMFAdjacent(i), TopAbs_EDGE); for (; anExpEA.More(); anExpEA.Next()) { @@ -448,7 +523,8 @@ private: //! @name Private methods performing the operation //! Extends the found adjacent faces and binds them to the original faces. void ExtendAdjacentFaces(const TopTools_IndexedMapOfShape& theMFAdjacent, - TopTools_IndexedDataMapOfShapeShape& theFaceExtFaceMap) + TopTools_IndexedDataMapOfShapeShape& theFaceExtFaceMap, + const Message_ProgressRange& theRange) { // Get the extension value for the faces - half of the diagonal of bounding box of the feature Bnd_Box aFeatureBox; @@ -457,7 +533,8 @@ private: //! @name Private methods performing the operation const Standard_Real anExtLength = sqrt(aFeatureBox.SquareExtent()); const Standard_Integer aNbFA = theMFAdjacent.Extent(); - for (Standard_Integer i = 1; i <= aNbFA; ++i) + Message_ProgressScope aPS(theRange, "Extending adjacent faces", aNbFA); + for (Standard_Integer i = 1; i <= aNbFA && aPS.More(); ++i, aPS.Next()) { const TopoDS_Face& aF = TopoDS::Face(theMFAdjacent(i)); // Extend the face @@ -473,7 +550,8 @@ private: //! @name Private methods performing the operation //! Trims the extended adjacent faces by intersection with each other //! and following intersection with the bounds of original faces. - void TrimExtendedFaces(const TopTools_IndexedDataMapOfShapeShape& theFaceExtFaceMap) + void TrimExtendedFaces(const TopTools_IndexedDataMapOfShapeShape& theFaceExtFaceMap, + const Message_ProgressRange& theRange) { // Intersect the extended faces first BOPAlgo_Builder aGFInter; @@ -486,9 +564,10 @@ private: //! @name Private methods performing the operation // Intersection result TopoDS_Shape anIntResult; + Message_ProgressScope aPSOuter(theRange, NULL, (aGFInter.Arguments().Extent() > 1) ? 2 : 1); if (aGFInter.Arguments().Extent() > 1) { - aGFInter.Perform(); + aGFInter.Perform(aPSOuter.Next()); if (aGFInter.HasErrors()) return; @@ -511,7 +590,8 @@ private: //! @name Private methods performing the operation TopTools_IndexedMapOfShape aFeatureEdgesMap; TopExp::MapShapes(myFeature, TopAbs_EDGE, aFeatureEdgesMap); - for (Standard_Integer i = 1; i <= aNbF; ++i) + Message_ProgressScope aPS(aPSOuter.Next(), "Trimming faces", aNbF); + for (Standard_Integer i = 1; i <= aNbF && aPS.More(); ++i, aPS.Next()) { const TopoDS_Face& aFOriginal = TopoDS::Face(theFaceExtFaceMap.FindKey(i)); const TopoDS_Face& aFExt = TopoDS::Face(theFaceExtFaceMap(i)); @@ -705,6 +785,7 @@ private: //! @name Fields TopoDS_Shape myFeature; //!< Feature to remove TopTools_IndexedDataMapOfShapeListOfShape* myEFMap; //!< EF Connection map to find adjacent faces TopTools_IndexedDataMapOfShapeListOfShape* myFSMap; //!< FS Connection map to find solids participating in the feature removal + Message_ProgressRange myRange; //!< Indication of progress // Results TopTools_MapOfShape myFeatureFacesMap; //!< Faces of the feature @@ -721,7 +802,7 @@ typedef NCollection_Vector VectorOfFillGap; // purpose: Remove features by filling the gaps by extension of the // adjacent faces //======================================================================= -void BOPAlgo_RemoveFeatures::RemoveFeatures() +void BOPAlgo_RemoveFeatures::RemoveFeatures(const Message_ProgressRange& theRange) { // For each feature: // - Find the faces adjacent to the feature; @@ -730,6 +811,8 @@ void BOPAlgo_RemoveFeatures::RemoveFeatures() // - Rebuild the solids with reconstructed adjacent faces // and avoiding the feature faces. + Message_ProgressScope aPSOuter(theRange, "Removing features", 2); + // Make Edge-Face connection map of the input // shape to find faces adjacent to the feature TopTools_IndexedDataMapOfShapeListOfShape anEFMap; @@ -755,9 +838,19 @@ void BOPAlgo_RemoveFeatures::RemoveFeatures() aFG.SetRunParallel(myRunParallel); } + const Standard_Integer aNbF = aVFG.Length(); + Message_ProgressScope aPS(aPSOuter.Next(), "Filling gaps", aNbF); + for (Standard_Integer i = 0; i < aNbF; ++i) + { + FillGap& aFG = aVFG.ChangeValue(i); + aFG.SetRange(aPS.Next()); + } // Perform the reconstruction of the adjacent faces BOPTools_Parallel::Perform (myRunParallel, aVFG); - + if (UserBreak(aPSOuter)) + { + return; + } // Even if the history is not requested, it is necessary to track: // - The solids modification after each feature removal to find // the necessary solids to rebuild on the next step. @@ -769,9 +862,13 @@ void BOPAlgo_RemoveFeatures::RemoveFeatures() // Remove the features one by one. // It will allow removing the features even if there were // some problems with removal of the previous features. - const Standard_Integer aNbF = aVFG.Length(); + Message_ProgressScope aPSLoop(aPSOuter.Next(), "Removing features one by one", aNbF); for (Standard_Integer i = 0; i < aNbF; ++i) { + if (UserBreak(aPSLoop)) + { + return; + } FillGap& aFG = aVFG(i); // No need to fill the history for solids if the history is not @@ -781,7 +878,7 @@ void BOPAlgo_RemoveFeatures::RemoveFeatures() // Perform removal of the single feature RemoveFeature(aFG.Feature(), aFG.Solids(), aFG.FeatureFacesMap(), aFG.HasAdjacentFaces(), aFG.Faces(), aFG.History(), - isSolidsHistoryNeeded); + isSolidsHistoryNeeded, aPSLoop.Next()); } } @@ -796,7 +893,8 @@ void BOPAlgo_RemoveFeatures::RemoveFeature const Standard_Boolean theHasAdjacentFaces, const TopTools_IndexedDataMapOfShapeListOfShape& theAdjFaces, const Handle(BRepTools_History)& theAdjFacesHistory, - const Standard_Boolean theSolidsHistoryNeeded) + const Standard_Boolean theSolidsHistoryNeeded, + const Message_ProgressRange& theRange) { Standard_Boolean bFuseShapes = Standard_True; const Standard_Integer aNbAF = theAdjFaces.Extent(); @@ -817,6 +915,7 @@ void BOPAlgo_RemoveFeatures::RemoveFeature bFuseShapes = Standard_False; } + Message_ProgressScope aPS(theRange, NULL, 100); // Rebuild the shape using MakerVolume algorithm avoiding the faces of the // feature and replacing the adjacent faces with their images @@ -848,7 +947,8 @@ void BOPAlgo_RemoveFeatures::RemoveFeature GetOriginalFaces(myShape, theSolids, theFeatureFacesMap, theAdjFaces, myHistory, aFacesToBeKept, anInternalShapes, aFacesToCheckOri, aSolidsToRebuild, aSharedFaces, anUnTouchedSolids); - + + aPS.Next(3); // To avoid excessive intersection of the faces collect the faces // of the input shape into a compound TopoDS_Compound anOrigF; @@ -898,7 +998,7 @@ void BOPAlgo_RemoveFeatures::RemoveFeature } // Build solids - aMV.Perform(); + aMV.Perform(aPS.Next(90)); if (aMV.HasErrors()) { // Add warning for the feature @@ -926,6 +1026,10 @@ void BOPAlgo_RemoveFeatures::RemoveFeature TopTools_MapOfShape anAdjFacesSplits; for (Standard_Integer i = 1; i <= aNbAF; ++i) { + if (!aPS.More()) + { + return; + } const TopoDS_Shape& aF = theAdjFaces.FindKey(i); const TopTools_ListOfShape& aLFIm = myHistory->Modified(aF); if (aLFIm.IsEmpty()) @@ -943,9 +1047,14 @@ void BOPAlgo_RemoveFeatures::RemoveFeature aNbFK = aFacesToBeKept.Extent(); for (Standard_Integer i = 1; i <= aNbFK && bValid; ++i) { + const TopoDS_Shape& aS = aFacesToBeKept(i); if (anAdjFacesSplits.Contains(aS)) continue; + if (!aPS.More()) + { + return; + } TopExp_Explorer anExpF(aS, TopAbs_FACE); for (; anExpF.More(); anExpF.Next()) { @@ -976,7 +1085,7 @@ void BOPAlgo_RemoveFeatures::RemoveFeature AddWarning(new BOPAlgo_AlertUnableToRemoveTheFeature(theFeature)); return; } - + aPS.Next(3); // Remove internal wires from the faces, possibly appeared after intersection RemoveInternalWires(aLSRes, &anInternalShapes); @@ -1000,7 +1109,7 @@ void BOPAlgo_RemoveFeatures::RemoveFeature MakeRemoved(anInternalShapes, aRemHist, aMSRes); myHistory->Merge(aRemHist); } - + aPS.Next(3); // Fill the history for the solids if (theSolidsHistoryNeeded) { @@ -1029,7 +1138,7 @@ void BOPAlgo_RemoveFeatures::RemoveFeature // function: UpdateHistory // purpose: Update history with the removed features //======================================================================= -void BOPAlgo_RemoveFeatures::UpdateHistory() +void BOPAlgo_RemoveFeatures::UpdateHistory(const Message_ProgressRange& theRange) { if (!HasHistory()) return; @@ -1042,7 +1151,8 @@ void BOPAlgo_RemoveFeatures::UpdateHistory() BRepTools_History aHistory; const Standard_Integer aNbS = myInputsMap.Extent(); - for (Standard_Integer i = 1; i <= aNbS; ++i) + Message_ProgressScope aPS(theRange, "Updating history", aNbS); + for (Standard_Integer i = 1; i <= aNbS; ++i, aPS.Next()) { const TopoDS_Shape& aS = myInputsMap(i); if (!BRepTools_History::IsSupportedType(aS)) @@ -1051,6 +1161,10 @@ void BOPAlgo_RemoveFeatures::UpdateHistory() if (myHistory->IsRemoved(aS)) continue; + if (UserBreak(aPS)) + { + return; + } // Check if the shape has any trace in the result const TopTools_ListOfShape& aLSIm = myHistory->Modified(aS); if (aLSIm.IsEmpty()) @@ -1075,10 +1189,11 @@ void BOPAlgo_RemoveFeatures::UpdateHistory() // purpose: Simplifies the result by removing extra edges and vertices // created during operation //======================================================================= -void BOPAlgo_RemoveFeatures::SimplifyResult() +void BOPAlgo_RemoveFeatures::SimplifyResult(const Message_ProgressRange& theRange) { if (myShape.IsSame(myInputShape)) return; + Message_ProgressScope aPSOuter(theRange, "Simplifyingthe result", 2); ShapeUpgrade_UnifySameDomain aSDTool; aSDTool.Initialize(myShape, Standard_True, Standard_True); // Do not allow producing internal edges @@ -1088,14 +1203,20 @@ void BOPAlgo_RemoveFeatures::SimplifyResult() TopExp::MapShapes(myShape, myMapShape); const Standard_Integer aNbS = myInputsMap.Extent(); - for (Standard_Integer i = 1; i <= aNbS; ++i) + Message_ProgressScope aPS(aPSOuter.Next(), NULL, aNbS); + for (Standard_Integer i = 1; i <= aNbS; ++i, aPS.Next()) { + if (UserBreak(aPS)) + { + return; + } if (myMapShape.Contains(myInputsMap(i))) aSDTool.KeepShape(myInputsMap(i)); } // Perform unification aSDTool.Build(); + aPSOuter.Next(); myShape = aSDTool.Shape(); if (HasHistory()) myHistory->Merge(aSDTool.History()); diff --git a/src/BOPAlgo/BOPAlgo_RemoveFeatures.hxx b/src/BOPAlgo/BOPAlgo_RemoveFeatures.hxx index 7db54ffa8c..1303bc8570 100644 --- a/src/BOPAlgo/BOPAlgo_RemoveFeatures.hxx +++ b/src/BOPAlgo/BOPAlgo_RemoveFeatures.hxx @@ -231,11 +231,11 @@ protected: //! @name Protected methods performing the removal //! Prepares the faces to remove: //! - Gets only faces contained in the input solids; //! - Builds connected blocks of faces creating separate features to remove. - Standard_EXPORT void PrepareFeatures(); + Standard_EXPORT void PrepareFeatures(const Message_ProgressRange& theRange); //! Removes the features and fills the created gaps by extension of the adjacent faces. //! Processes each feature separately. - Standard_EXPORT void RemoveFeatures(); + Standard_EXPORT void RemoveFeatures(const Message_ProgressRange& theRange); //! Remove the single feature from the shape. //! @param theFeature [in] The feature to remove; @@ -253,18 +253,22 @@ protected: //! @name Protected methods performing the removal const Standard_Boolean theHasAdjacentFaces, const TopTools_IndexedDataMapOfShapeListOfShape& theAdjFaces, const Handle(BRepTools_History)& theAdjFacesHistory, - const Standard_Boolean theSolidsHistoryNeeded); + const Standard_Boolean theSolidsHistoryNeeded, + const Message_ProgressRange& theRange); //! Updates history with the removed features - Standard_EXPORT void UpdateHistory(); + Standard_EXPORT void UpdateHistory(const Message_ProgressRange& theRange); //! Simplifies the result by removing extra edges and vertices created //! during removal of the features. - Standard_EXPORT void SimplifyResult(); + Standard_EXPORT void SimplifyResult(const Message_ProgressRange& theRange); //! Post treatment - restore the type of the initial shape Standard_EXPORT void PostTreat(); + //! Filling steps for constant operations + Standard_EXPORT void fillPIConstants(const Standard_Real theWhole, BOPAlgo_PISteps& theSteps) const Standard_OVERRIDE; + protected: //! @name Fields // Inputs diff --git a/src/BOPTest/BOPTest_RemoveFeaturesCommands.cxx b/src/BOPTest/BOPTest_RemoveFeaturesCommands.cxx index 7a85b1d099..2f00af4c38 100644 --- a/src/BOPTest/BOPTest_RemoveFeaturesCommands.cxx +++ b/src/BOPTest/BOPTest_RemoveFeaturesCommands.cxx @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -98,9 +99,9 @@ Standard_Integer RemoveFeatures(Draw_Interpretor& theDI, } aRF.SetToFillHistory(BRepTest_Objects::IsHistoryNeeded()); - + Handle(Draw_ProgressIndicator) aProgress = new Draw_ProgressIndicator(theDI, 1); // Perform the removal - aRF.Build(); + aRF.Build(aProgress->Start()); // Check for the errors/warnings BOPTest::ReportAlerts(aRF.GetReport()); diff --git a/src/BRepAlgoAPI/BRepAlgoAPI_Defeaturing.cxx b/src/BRepAlgoAPI/BRepAlgoAPI_Defeaturing.cxx index 2f4def8b8d..04fa1a3dbd 100644 --- a/src/BRepAlgoAPI/BRepAlgoAPI_Defeaturing.cxx +++ b/src/BRepAlgoAPI/BRepAlgoAPI_Defeaturing.cxx @@ -21,7 +21,7 @@ //function : Build //purpose : //======================================================================= -void BRepAlgoAPI_Defeaturing::Build(const Message_ProgressRange& /*theRange*/) +void BRepAlgoAPI_Defeaturing::Build(const Message_ProgressRange& theRange) { // Set not done state for the operation NotDone(); @@ -36,7 +36,7 @@ void BRepAlgoAPI_Defeaturing::Build(const Message_ProgressRange& /*theRange*/) myFeatureRemovalTool.SetRunParallel(myRunParallel); // Perform the features removal - myFeatureRemovalTool.Perform(); + myFeatureRemovalTool.Perform(theRange); // Merge the Errors/Warnings from the features removal tool GetReport()->Merge(myFeatureRemovalTool.GetReport()); diff --git a/tests/bugs/modalg_7/bug30788 b/tests/bugs/modalg_7/bug30788 new file mode 100644 index 0000000000..a0ebc39615 --- /dev/null +++ b/tests/bugs/modalg_7/bug30788 @@ -0,0 +1,22 @@ +puts "============================================" +puts "0030788: Modeling Algorithms - BRepAlgoAPI_Defeaturing does not propagate progress indicator to underlying algorithms" +puts "============================================" +puts "" + +proc isTracked { theOutput } { + if {![regexp "Progress" $theOutput]} { + puts "Error: progress is not tracked" + } +} + +XProgress +t + +restore [locate_data_file bug29481_ex1.brep] s +explode s f + +compound s_6 s_18 step + +# check that progress is tracked for removefeatures operation + +set log [removefeatures res s step] +isTracked $log