// Created by: Eugeny MALTCHIKOV // Copyright (c) 2018 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //======================================================================= // static methods declaration //======================================================================= static void MakeRemoved(const TopTools_ListOfShape& theShapes, BRepTools_History& theHistory, const TopTools_IndexedMapOfShape& theKeepShapes = TopTools_IndexedMapOfShape()); static void FindInternals(const TopoDS_Shape& theS, TopTools_ListOfShape& theLInt); static void RemoveInternalWires(const TopTools_ListOfShape& theShapes, TopTools_ListOfShape* theRemoved = NULL); static void GetOriginalFaces(const TopoDS_Shape& theShape, const TopTools_IndexedMapOfShape& theSolids, const TopTools_MapOfShape& theFeatureFacesMap, const TopTools_IndexedDataMapOfShapeListOfShape& theAdjFaces, const Handle(BRepTools_History)& theHistory, TopTools_IndexedMapOfShape& theFacesToBeKept, TopTools_ListOfShape& theInternalShapes, TopTools_MapOfShape& theFacesToCheckOri, TopTools_IndexedMapOfShape& theSolidsToRebuild, TopTools_ListOfShape& theSharedFaces, TopTools_ListOfShape& theUnTouchedSolids); static void FindShape(const TopoDS_Shape& theSWhat, const TopoDS_Shape& theSWhere, TopoDS_Shape& theSFound); static void GetValidSolids(BOPAlgo_MakerVolume& theMV, const TopTools_MapOfShape& theFacesToCheckOri, const TopTools_ListOfShape& aSharedFaces, const TopoDS_Shape& theOrigFaces, const Standard_Integer theNbSol, TopTools_ListOfShape& theLSRes, TopTools_ListOfShape& theRemovedShapes); static void FindExtraShapes(const TopTools_IndexedDataMapOfShapeListOfShape& theConnectionMap, const TopTools_MapOfShape& theShapesToCheckOri, BOPAlgo_Builder& theBuilder, TopTools_MapOfShape& theShapesToAvoid, TopTools_MapOfShape* theValidShapes = NULL); static void AvoidExtraSharedFaces(TopTools_ListOfShape& theLSolids, const TopTools_ListOfShape& theLFSharedToAvoid, BOPAlgo_Builder& theBuilder, TopTools_ListOfShape& theExtraFaces); static void FillSolidsHistory(const TopTools_IndexedMapOfShape& theSolIn, TopTools_ListOfShape& theSolidsRes, const TopTools_IndexedDataMapOfShapeListOfShape& theAdjFaces, BOPAlgo_Builder& theBuilder, BRepTools_History& theSolidsHistory); static void TakeModified(const TopoDS_Shape& theS, BOPAlgo_Builder& theBuilder, TopTools_ListOfShape& theList); static void TakeModified(const TopoDS_Shape& theS, BOPAlgo_Builder& theBuilder, TopTools_MapOfShape& theMap); static void FindSolid(const TopoDS_Shape& theSolIn, const TopTools_ListOfShape& theSolidsRes, const TopTools_IndexedDataMapOfShapeListOfShape& theAdjFaces, BOPAlgo_Builder& theBuilder, TopoDS_Shape& theSolOut); //======================================================================= // function: Perform // purpose: Performs the removal of the requested faces from the input shape //======================================================================= void BOPAlgo_RemoveFeatures::Perform() { try { OCC_CATCH_SIGNALS if (HasHistory()) myHistory = new BRepTools_History(); // Check the input data CheckData(); if (HasErrors()) return; // Prepare the faces to remove. PrepareFeatures(); if (HasErrors()) return; // Remove the features and fill the created gaps RemoveFeatures(); // Update history with the removed features UpdateHistory(); // Simplify the result SimplifyResult(); // Post treatment PostTreat(); } catch (Standard_Failure const&) { AddError(new BOPAlgo_AlertRemoveFeaturesFailed()); } } //======================================================================= // function: CheckData // purpose: Checks the input data on validity for the algorithm //======================================================================= void BOPAlgo_RemoveFeatures::CheckData() { // Prepare the shape to work with myShape = myInputShape; // Check the type of input shape const TopAbs_ShapeEnum aType = myInputShape.ShapeType(); if (aType == TopAbs_SOLID || aType == TopAbs_COMPSOLID) return; // OK if (aType == TopAbs_COMPOUND) { TopTools_ListOfShape aShapes; TopTools_MapOfShape aMFence; // Extract all shapes from the compound BOPAlgo_Tools::TreatCompound(myInputShape, aMFence, aShapes); if (aShapes.IsEmpty()) { // Add error of empty input shape AddError(new BOPAlgo_AlertEmptyShape(myInputShape)); return; } // Find all solids in the list of shapes TopTools_ListOfShape aSolids; TopTools_ListOfShape anOtherShapes; TopTools_ListIteratorOfListOfShape aIt(aShapes); for (; aIt.More(); aIt.Next()) { const TopoDS_Shape& aS = aIt.Value(); if (aS.ShapeType() == TopAbs_SOLID || aS.ShapeType() == TopAbs_COMPSOLID) aSolids.Append(aS); else anOtherShapes.Append(aS); } if (aSolids.IsEmpty()) { // No solids have been found for processing. // Add error of unsupported type of input shape AddError(new BOPAlgo_AlertTooFewArguments()); } else if (anOtherShapes.Extent() > 0) { // Add warning of unsupported type of input shape for all // non-solid shapes, contained in the input shape for (aIt.Initialize(anOtherShapes); aIt.More(); aIt.Next()) { AddWarning(new BOPAlgo_AlertUnsupportedType(aIt.Value())); } // Collect all solids into compound and overwrite the shape to rebuild TopoDS_Compound aCS; BRep_Builder().MakeCompound(aCS); for (aIt.Initialize(aSolids); aIt.More(); aIt.Next()) BRep_Builder().Add(aCS, aIt.Value()); myShape = aCS; if (HasHistory()) { // Make non solid shapes removed in the history MakeRemoved(anOtherShapes, *myHistory.get()); } } } else { // Add error of unsupported type of input shape AddError(new BOPAlgo_AlertTooFewArguments()); } } //======================================================================= // function: PrepareFeatures // purpose: Prepares the features to remove //======================================================================= void BOPAlgo_RemoveFeatures::PrepareFeatures() { // Map all sub-shapes of the input solids TopExp::MapShapes(myInputShape, myInputsMap); // Collect all faces of the input shape requested for removal TopTools_ListOfShape aFacesToRemove; TopTools_ListIteratorOfListOfShape aIt(myFacesToRemove); for (; aIt.More(); aIt.Next()) { const TopoDS_Shape& aS = aIt.Value(); TopExp_Explorer anExpF(aS, TopAbs_FACE); for (; anExpF.More(); anExpF.Next()) { const TopoDS_Shape& aF = anExpF.Current(); if (myInputsMap.Contains(aF)) aFacesToRemove.Append(aF); } } if (aFacesToRemove.IsEmpty()) { // Add error, that no features to remove have been found AddError(new BOPAlgo_AlertNoFacesToRemove()); return; } // Build connexity blocks of the faces to remove TopoDS_Compound aCFToRemove; BRep_Builder().MakeCompound(aCFToRemove); for (aIt.Initialize(aFacesToRemove); aIt.More(); aIt.Next()) BRep_Builder().Add(aCFToRemove, aIt.Value()); // Fill the list of features with connexity blocks of faces BOPTools_AlgoTools::MakeConnexityBlocks(aCFToRemove, TopAbs_EDGE, TopAbs_FACE, myFeatures); } //======================================================================= // Adjacent faces extension block //======================================================================= // class: FillGaps // purpose: Auxiliary class for creation of the faces for filling the gap // created by removal of the single feature //======================================================================= class FillGap { public: //! @name Constructors //! Empty constructor FillGap() : myRunParallel(Standard_False), myHasAdjacentFaces(Standard_False) {} public: //! @name Setters/Getters //! Sets the feature to remove void SetFeature(const TopoDS_Shape& theFeature) { myFeature = theFeature; } //! Returns the feature const TopoDS_Shape& Feature() const { return myFeature; } //! Sets the EF connection map void SetEFConnectionMap(const TopTools_IndexedDataMapOfShapeListOfShape& theEFMap) { myEFMap = (TopTools_IndexedDataMapOfShapeListOfShape*)&theEFMap; } //! Sets the FS connection map void SetFSConnectionMap(const TopTools_IndexedDataMapOfShapeListOfShape& theFSMap) { myFSMap = (TopTools_IndexedDataMapOfShapeListOfShape*)&theFSMap; } //! Defines the parallel processing mode void SetRunParallel(const Standard_Boolean bRunParallel) { myRunParallel = bRunParallel; } //! Gets the History object const Handle(BRepTools_History)& History() { return myHistory; } public: //! @name Perform the operation //! Performs the extension of the adjacent faces and //! then trims the extended faces to fill the gaps void Perform() { OCC_CATCH_SIGNALS try { myHistory = new BRepTools_History(); // Find the faces adjacent to the faces of the feature TopTools_IndexedMapOfShape aMFAdjacent; FindAdjacentFaces(aMFAdjacent); myHasAdjacentFaces = (aMFAdjacent.Extent() > 0); if (!myHasAdjacentFaces) return; // Extend the adjacent faces keeping the connection to the original faces TopTools_IndexedDataMapOfShapeShape aFaceExtFaceMap; ExtendAdjacentFaces(aMFAdjacent, aFaceExtFaceMap); // Trim the extended faces TrimExtendedFaces(aFaceExtFaceMap); } catch (Standard_Failure const&) { // Make sure the warning will be given on the higher level myHasAdjacentFaces = Standard_True; myFaces.Clear(); } } public: //! @name Obtain the result //! Returns the map of faces of the feature const TopTools_MapOfShape& FeatureFacesMap() const { return myFeatureFacesMap; } //! Shows whether the adjacent faces have been found for the feature Standard_Boolean HasAdjacentFaces() const { return myHasAdjacentFaces; } //! Returns the Images map of the adjacent faces const TopTools_IndexedDataMapOfShapeListOfShape& Faces() const { return myFaces; } //! Returns the initial solids participating in the feature removal const TopTools_IndexedMapOfShape& Solids() const { return mySolids; } 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) { // 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()); // Find faces adjacent to the feature using the connection map aIt.Initialize(myFeature); for (; aIt.More(); aIt.Next()) { const TopoDS_Shape& aF = aIt.Value(); TopExp_Explorer anExpE(aF, TopAbs_EDGE); for (; anExpE.More(); anExpE.Next()) { const TopoDS_Shape& aE = anExpE.Current(); const TopTools_ListOfShape* pAdjacentFaces = myEFMap->Seek(aE); if (pAdjacentFaces) { TopTools_ListIteratorOfListOfShape itLFA(*pAdjacentFaces); for (; itLFA.More(); itLFA.Next()) { const TopoDS_Shape& anAF = itLFA.Value(); if (!myFeatureFacesMap.Contains(anAF)) theMFAdjacent.Add(anAF); } } } // Find solids containing the feature face const TopTools_ListOfShape* pLS = myFSMap->Seek(aF); if (pLS) { TopTools_ListIteratorOfListOfShape itLS(*pLS); for (; itLS.More(); itLS.Next()) mySolids.Add(itLS.Value()); } } // Find solids containing the edges of adjacent faces const Standard_Integer aNbFA = theMFAdjacent.Extent(); for (Standard_Integer i = 1; i <= aNbFA; ++i) { TopExp_Explorer anExpEA(theMFAdjacent(i), TopAbs_EDGE); for (; anExpEA.More(); anExpEA.Next()) { // Faces adjacent to the face adjacent to the feature const TopTools_ListOfShape* pLFAA = myEFMap->Seek(anExpEA.Current()); if (pLFAA) { TopTools_ListIteratorOfListOfShape itLFAA(*pLFAA); for (; itLFAA.More(); itLFAA.Next()) { // Solids containing the faces const TopTools_ListOfShape* pLS = myFSMap->Seek(itLFAA.Value()); if (pLS) { TopTools_ListIteratorOfListOfShape itLS(*pLS); for (; itLS.More(); itLS.Next()) mySolids.Add(itLS.Value()); } } } } } } //! Extends the found adjacent faces and binds them to the original faces. void ExtendAdjacentFaces(const TopTools_IndexedMapOfShape& theMFAdjacent, TopTools_IndexedDataMapOfShapeShape& theFaceExtFaceMap) { // Get the extension value for the faces - half of the diagonal of bounding box of the feature Bnd_Box aFeatureBox; BRepBndLib::Add(myFeature, aFeatureBox); const Standard_Real anExtLength = sqrt(aFeatureBox.SquareExtent()); const Standard_Integer aNbFA = theMFAdjacent.Extent(); for (Standard_Integer i = 1; i <= aNbFA; ++i) { const TopoDS_Face& aF = TopoDS::Face(theMFAdjacent(i)); // Extend the face TopoDS_Face aFExt; BRepLib::ExtendFace(aF, anExtLength, Standard_True, Standard_True, Standard_True, Standard_True, aFExt); theFaceExtFaceMap.Add(aF, aFExt); myHistory->AddModified(aF, aFExt); } } //! 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) { // Intersect the extended faces first BOPAlgo_Builder aGFInter; // Add faces for intersection const Standard_Integer aNbF = theFaceExtFaceMap.Extent(); for (Standard_Integer i = 1; i <= aNbF; ++i) aGFInter.AddArgument(theFaceExtFaceMap(i)); aGFInter.SetRunParallel(myRunParallel); // Intersection result TopoDS_Shape anIntResult; if (aGFInter.Arguments().Extent() > 1) { aGFInter.Perform(); if (aGFInter.HasErrors()) return; anIntResult = aGFInter.Shape(); myHistory->Merge(aGFInter.History()); } else anIntResult = aGFInter.Arguments().First(); // Prepare the EF map of the extended faces after intersection // to select from them only boundary edges TopTools_IndexedDataMapOfShapeListOfShape anEFExtMap; TopExp::MapShapesAndAncestors(anIntResult, TopAbs_EDGE, TopAbs_FACE, anEFExtMap); // Get the splits of the extended faces after intersection // and trim them by the edges of the original faces // Map the edges of the Feature to avoid them during the trim TopTools_IndexedMapOfShape aFeatureEdgesMap; TopExp::MapShapes(myFeature, TopAbs_EDGE, aFeatureEdgesMap); for (Standard_Integer i = 1; i <= aNbF; ++i) { const TopoDS_Face& aFOriginal = TopoDS::Face(theFaceExtFaceMap.FindKey(i)); const TopoDS_Face& aFExt = TopoDS::Face(theFaceExtFaceMap(i)); TrimFace(aFExt, aFOriginal, aFeatureEdgesMap, anEFExtMap, aGFInter); } } //! Trim the extended faces by the bounds of the original face, //! except those contained in the feature to remove. void TrimFace(const TopoDS_Face& theFExt, const TopoDS_Face& theFOriginal, const TopTools_IndexedMapOfShape& theFeatureEdgesMap, const TopTools_IndexedDataMapOfShapeListOfShape& theEFExtMap, BOPAlgo_Builder& theGFInter) { // Map all edges of the extended face, to filter the result of trim // from the faces containing these edges TopTools_MapOfShape aMExtEdges; TopExp_Explorer anExpE(theFExt, TopAbs_EDGE); for (; anExpE.More(); anExpE.Next()) { const TopoDS_Edge& aE = TopoDS::Edge(anExpE.Current()); // skip degenerated and seam edges if (BRep_Tool::Degenerated(aE) || BRep_Tool::IsClosed(aE, theFExt)) continue; TopTools_ListOfShape aLEIm; TakeModified(aE, theGFInter, aLEIm); TopTools_ListIteratorOfListOfShape itLEIm(aLEIm); for (; itLEIm.More(); itLEIm.Next()) { const TopoDS_Shape& aEIm = itLEIm.Value(); if (theEFExtMap.FindFromKey(aEIm).Extent() == 1) aMExtEdges.Add(aEIm); } } // Trimming tool BOPAlgo_Builder aGFTrim; // Get the splits of the face and add them for trimming TopTools_ListOfShape anExtSplits; TakeModified(theFExt, theGFInter, anExtSplits); aGFTrim.SetArguments(anExtSplits); // Add edges of the original faces TopTools_MapOfShape aMEdgesToCheckOri; anExpE.Init(theFOriginal, TopAbs_EDGE); for (; anExpE.More(); anExpE.Next()) { const TopoDS_Edge& aE = TopoDS::Edge(anExpE.Current()); if (!theFeatureEdgesMap.Contains(aE)) { aGFTrim.AddArgument(aE); if (!BRep_Tool::Degenerated(aE) && !BRep_Tool::IsClosed(aE, theFOriginal)) { if (!aMEdgesToCheckOri.Add(aE)) aMEdgesToCheckOri.Remove(aE); } } } // Avoid faces intersection aGFTrim.SetGlue(BOPAlgo_GlueShift); aGFTrim.SetRunParallel(myRunParallel); aGFTrim.SetNonDestructive(Standard_True); aGFTrim.Perform(); if (aGFTrim.HasErrors()) return; // Get all splits const TopoDS_Shape& aSplits = aGFTrim.Shape(); // Filter the trimmed faces and save the valid ones into result map TopTools_ListOfShape aLFTrimmed; TopExp_Explorer anExpF(aSplits, TopAbs_FACE); for (; anExpF.More(); anExpF.Next()) { const TopoDS_Shape& aSp = anExpF.Current(); anExpE.Init(aSp, TopAbs_EDGE); for (; anExpE.More(); anExpE.Next()) { if (aMExtEdges.Contains(anExpE.Current())) break; } if (!anExpE.More()) aLFTrimmed.Append(aSp); } if (aLFTrimmed.Extent() > 1) { // Chose the correct faces - the ones that contains edges with proper // bi-normal direction TopTools_IndexedDataMapOfShapeListOfShape anEFMap; TopTools_ListIteratorOfListOfShape itLF(aLFTrimmed); for (; itLF.More(); itLF.Next()) TopExp::MapShapesAndAncestors(itLF.Value(), TopAbs_EDGE, TopAbs_FACE, anEFMap); // Check edges orientations TopTools_MapOfShape aFacesToAvoid, aValidFaces; FindExtraShapes(anEFMap, aMEdgesToCheckOri, aGFTrim, aFacesToAvoid, &aValidFaces); if (aLFTrimmed.Extent() - aFacesToAvoid.Extent() > 1) { // It is possible that the splits are forming the different blocks. // Take only those containing the valid faces. TopoDS_Compound aCF; BRep_Builder().MakeCompound(aCF); itLF.Initialize(aLFTrimmed); for (; itLF.More(); itLF.Next()) { if (!aFacesToAvoid.Contains(itLF.Value())) BRep_Builder().Add(aCF, itLF.Value()); } TopTools_ListOfShape aLCB; BOPTools_AlgoTools::MakeConnexityBlocks(aCF, TopAbs_EDGE, TopAbs_FACE, aLCB); if (aLCB.Extent() > 1) { TopTools_ListIteratorOfListOfShape itLCB(aLCB); for (; itLCB.More(); itLCB.Next()) { // Check if the block contains any valid faces const TopoDS_Shape& aCB = itLCB.Value(); TopoDS_Iterator itF(aCB); for (; itF.More(); itF.Next()) { if (aValidFaces.Contains(itF.Value())) break; } if (!itF.More()) { // Invalid block for (itF.Initialize(aCB); itF.More(); itF.Next()) aFacesToAvoid.Add(itF.Value()); } } } } itLF.Initialize(aLFTrimmed); for (; itLF.More();) { if (aFacesToAvoid.Contains(itLF.Value())) aLFTrimmed.Remove(itLF); else itLF.Next(); } } else if (aLFTrimmed.IsEmpty()) { // Use all splits, including those having the bounds of extended face anExpF.ReInit(); for (; anExpF.More(); anExpF.Next()) aLFTrimmed.Append(anExpF.Current()); } if (aLFTrimmed.Extent()) { // Remove the internal edges and vertices from the faces RemoveInternalWires(aLFTrimmed); myFaces.Add(theFOriginal, aLFTrimmed); } // Update history after intersection of the extended face with bounds myHistory->Merge(aGFTrim.History()); // Update history with all removed shapes BRepTools_History aHistRem; // Map of the result splits TopTools_IndexedMapOfShape aResMap; TopTools_ListIteratorOfListOfShape itLF(aLFTrimmed); for (; itLF.More(); itLF.Next()) TopExp::MapShapes(itLF.Value(), aResMap); TopTools_ListOfShape aLSplits; aLSplits.Append(aSplits); // Update the history with removed shapes MakeRemoved(aLSplits, aHistRem, aResMap); myHistory->Merge(aHistRem); } private: //! @name Fields // Inputs Standard_Boolean myRunParallel; //!< Defines the mode of processing of the single feature 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 // Results TopTools_MapOfShape myFeatureFacesMap; //!< Faces of the feature Standard_Boolean myHasAdjacentFaces; //!< Flag to show whether the adjacent faces have been found or not TopTools_IndexedMapOfShape mySolids; //!< Solids participating in the feature removal TopTools_IndexedDataMapOfShapeListOfShape myFaces; //!< Reconstructed adjacent faces Handle(BRepTools_History) myHistory; //!< History of the adjacent faces reconstruction }; typedef NCollection_Vector VectorOfFillGap; typedef BOPTools_Functor FillGapFunctor; typedef BOPTools_Cnt FillGapCnt; //======================================================================= //======================================================================= // function: RemoveFeatures // purpose: Remove features by filling the gaps by extension of the // adjacent faces //======================================================================= void BOPAlgo_RemoveFeatures::RemoveFeatures() { // For each feature: // - Find the faces adjacent to the feature; // - Extend the adjacent faces; // - Trim the extended faces to fill the gap; // - Rebuild the solids with reconstructed adjacent faces // and avoiding the feature faces. // Make Edge-Face connection map of the input // shape to find faces adjacent to the feature TopTools_IndexedDataMapOfShapeListOfShape anEFMap; TopExp::MapShapesAndAncestors(myInputShape, TopAbs_EDGE, TopAbs_FACE, anEFMap); // Make Face-Solid connection map to find the solids // participating in the removal of each feature TopTools_IndexedDataMapOfShapeListOfShape anFSMap; TopExp::MapShapesAndAncestors(myInputShape, TopAbs_FACE, TopAbs_SOLID, anFSMap); // Tool for reconstruction of the faces adjacent to the feature // in parallel threads if necessary. VectorOfFillGap aVFG; // Fill the vector TopTools_ListIteratorOfListOfShape itF(myFeatures); for (; itF.More(); itF.Next()) { const TopoDS_Shape& aFeature = itF.Value(); FillGap& aFG = aVFG.Appended(); aFG.SetFeature(aFeature); aFG.SetEFConnectionMap(anEFMap); aFG.SetFSConnectionMap(anFSMap); aFG.SetRunParallel(myRunParallel); } // Perform the reconstruction of the adjacent faces FillGapCnt::Perform(myRunParallel, aVFG); // 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. // - The faces modification after each feature removal to find the // splits of the adjacent and feature faces for the next steps. if (myHistory.IsNull()) myHistory = new BRepTools_History(); // 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(); for (Standard_Integer i = 0; i < aNbF; ++i) { FillGap& aFG = aVFG(i); // No need to fill the history for solids if the history is not // requested and the current feature is the last one. Standard_Boolean isSolidsHistoryNeeded = HasHistory() || (i < (aNbF - 1)); // Perform removal of the single feature RemoveFeature(aFG.Feature(), aFG.Solids(), aFG.FeatureFacesMap(), aFG.HasAdjacentFaces(), aFG.Faces(), aFG.History(), isSolidsHistoryNeeded); } } //======================================================================= // function: RemoveFeature // purpose: Remove the single feature //======================================================================= void BOPAlgo_RemoveFeatures::RemoveFeature (const TopoDS_Shape& theFeature, const TopTools_IndexedMapOfShape& theSolids, const TopTools_MapOfShape& theFeatureFacesMap, const Standard_Boolean theHasAdjacentFaces, const TopTools_IndexedDataMapOfShapeListOfShape& theAdjFaces, const Handle(BRepTools_History)& theAdjFacesHistory, const Standard_Boolean theSolidsHistoryNeeded) { Standard_Boolean bFuseShapes = Standard_True; const Standard_Integer aNbAF = theAdjFaces.Extent(); if (aNbAF == 0) { if (theHasAdjacentFaces) { // The adjacent faces have been found for the feature, // but something went wrong during their rebuilding. // Add error AddWarning(new BOPAlgo_AlertUnableToRemoveTheFeature(theFeature)); return; } // No adjacent faces have been found for the feature. // Most likely, the intention is to remove some internal part of the shape. // We just have to rebuild the shape without the feature, no fuse is necessary. bFuseShapes = Standard_False; } // Rebuild the shape using MakerVolume algorithm avoiding the faces of the // feature and replacing the adjacent faces with their images BRep_Builder aBB; // From the faces of input shape build map of faces with which the result will be validated: // - all non-internal faces of the input shape (except for adjacent and feature faces) // must have some trace in the result solids; // - all adjacent faces (if any) must have some trace in the result solids. TopTools_IndexedMapOfShape aFacesToBeKept; // Build also the map of faces to compare orientation of the original and result faces TopTools_MapOfShape aFacesToCheckOri; // Collect list of internal entities of the input shape to be avoided in result // and to make them removed in the history. TopTools_ListOfShape anInternalShapes; // In the feature removal will participate only the solids connected to the feature // or the faces adjacent to the feature. // Solids to be rebuilt after the feature removal TopTools_IndexedMapOfShape aSolidsToRebuild; // Find faces shared between solids TopTools_ListOfShape aSharedFaces; // Solids to be avoided in the feature removal and added into result directly TopTools_ListOfShape anUnTouchedSolids; // Prepare to the feature removal - fill all necessary containers GetOriginalFaces(myShape, theSolids, theFeatureFacesMap, theAdjFaces, myHistory, aFacesToBeKept, anInternalShapes, aFacesToCheckOri, aSolidsToRebuild, aSharedFaces, anUnTouchedSolids); // To avoid excessive intersection of the faces collect the faces // of the input shape into a compound TopoDS_Compound anOrigF; aBB.MakeCompound(anOrigF); Standard_Integer aNbFK = aFacesToBeKept.Extent(); for (Standard_Integer i = 1; i <= aNbFK; ++i) aBB.Add(anOrigF, aFacesToBeKept(i)); // Tool for solids reconstruction BOPAlgo_MakerVolume aMV; aMV.SetRunParallel(myRunParallel); aMV.SetAvoidInternalShapes(Standard_True); aMV.SetIntersect(bFuseShapes); aMV.SetNonDestructive(Standard_True); // Add faces of the input shape aMV.AddArgument(anOrigF); // Add reconstructed adjacent faces for (Standard_Integer i = 1; i <= aNbAF; ++i) { const TopTools_ListOfShape& aLFA = theAdjFaces(i); if (aLFA.Extent() == 1) { const TopoDS_Shape& aFA = aLFA.First(); aMV.AddArgument(aFA); aFacesToBeKept.Add(aFA); } else { // To avoid intersection among the images, collect them into compound TopoDS_Compound anAdjF; aBB.MakeCompound(anAdjF); TopTools_ListIteratorOfListOfShape itLFA(aLFA); for (; itLFA.More(); itLFA.Next()) aBB.Add(anAdjF, itLFA.Value()); aMV.AddArgument(anAdjF); aFacesToBeKept.Add(anAdjF); } if (HasHistory()) { // Look for internal edges in the original adjacent faces const TopoDS_Shape& aFOr = theAdjFaces.FindKey(i); FindInternals(aFOr, anInternalShapes); } } // Build solids aMV.Perform(); if (aMV.HasErrors()) { // Add warning for the feature AddWarning(new BOPAlgo_AlertUnableToRemoveTheFeature(theFeature)); return; } // Result of MV operation const TopoDS_Shape& aSolids = aMV.Shape(); TopExp_Explorer anExpS(aSolids, TopAbs_SOLID); if (!anExpS.More()) { // No solids have been built - add warning for the feature AddWarning(new BOPAlgo_AlertUnableToRemoveTheFeature(theFeature)); return; } // Now, it is necessary to: // - Validate the result by checking faces of the map // to have some parts kept in the resulting solids; // - Remove the solids possibly filling the holes in the original shapes; // - Update history with the history of MakerVolume algorithm. // Splits of adjacent faces from previous runs TopTools_MapOfShape anAdjFacesSplits; for (Standard_Integer i = 1; i <= aNbAF; ++i) { const TopoDS_Shape& aF = theAdjFaces.FindKey(i); const TopTools_ListOfShape& aLFIm = myHistory->Modified(aF); if (aLFIm.IsEmpty()) anAdjFacesSplits.Add(aF); else { TopTools_ListIteratorOfListOfShape itLFIm(aLFIm); for (; itLFIm.More(); itLFIm.Next()) anAdjFacesSplits.Add(itLFIm.Value()); } } // Validate the result Standard_Boolean bValid = Standard_True; aNbFK = aFacesToBeKept.Extent(); for (Standard_Integer i = 1; i <= aNbFK && bValid; ++i) { const TopoDS_Shape& aS = aFacesToBeKept(i); if (anAdjFacesSplits.Contains(aS)) continue; TopExp_Explorer anExpF(aS, TopAbs_FACE); for (; anExpF.More(); anExpF.Next()) { const TopoDS_Shape& aF = anExpF.Current(); if (!aMV.IsDeleted(aF)) break; } bValid = anExpF.More(); } if (!bValid) { // Add warning for the feature AddWarning(new BOPAlgo_AlertUnableToRemoveTheFeature(theFeature)); return; } // It is possible that the result of MakerVolume operation contains // some extra solids. Get only correct solids. TopTools_ListOfShape aLSRes; // Remember the removed shapes TopTools_ListOfShape aRemovedShapes; GetValidSolids(aMV, aFacesToCheckOri, aSharedFaces, anOrigF, theSolids.Extent(), aLSRes, aRemovedShapes); if (aLSRes.Extent() != theSolids.Extent()) { // Add warning for the feature AddWarning(new BOPAlgo_AlertUnableToRemoveTheFeature(theFeature)); return; } // Remove internal wires from the faces, possibly appeared after intersection RemoveInternalWires(aLSRes, &anInternalShapes); // Update history with: // History of adjacent faces reconstruction myHistory->Merge(theAdjFacesHistory); // History of intersection myHistory->Merge(aMV.History()); if (HasHistory()) { // Map the result to check if the shape is removed TopTools_IndexedMapOfShape aMSRes; TopTools_ListIteratorOfListOfShape itLS(aLSRes); for (; itLS.More(); itLS.Next()) TopExp::MapShapes(itLS.Value(), aMSRes); // Remove internal shapes and extra faces BRepTools_History aRemHist; anInternalShapes.Append(aRemovedShapes); MakeRemoved(anInternalShapes, aRemHist, aMSRes); myHistory->Merge(aRemHist); } // Fill the history for the solids if (theSolidsHistoryNeeded) { BRepTools_History aSolidsHistory; FillSolidsHistory(aSolidsToRebuild, aLSRes, theAdjFaces, aMV, aSolidsHistory); myHistory->Merge(aSolidsHistory); } TopoDS_Compound aCRes; aBB.MakeCompound(aCRes); // Add reconstructed solids TopTools_ListIteratorOfListOfShape itLS(aLSRes); for (; itLS.More(); itLS.Next()) aBB.Add(aCRes, itLS.Value()); // Add unmodified solids itLS.Initialize(anUnTouchedSolids); for (; itLS.More(); itLS.Next()) aBB.Add(aCRes, itLS.Value()); // Save the result myShape = aCRes; } //======================================================================= // function: UpdateHistory // purpose: Update history with the removed features //======================================================================= void BOPAlgo_RemoveFeatures::UpdateHistory() { if (!HasHistory()) return; // Map the result myMapShape.Clear(); TopExp::MapShapes(myShape, myMapShape); // Update the history BRepTools_History aHistory; const Standard_Integer aNbS = myInputsMap.Extent(); for (Standard_Integer i = 1; i <= aNbS; ++i) { const TopoDS_Shape& aS = myInputsMap(i); if (!BRepTools_History::IsSupportedType(aS)) continue; if (myHistory->IsRemoved(aS)) continue; // Check if the shape has any trace in the result const TopTools_ListOfShape& aLSIm = myHistory->Modified(aS); if (aLSIm.IsEmpty()) { if (!myMapShape.Contains(aS)) aHistory.Remove(aS); } TopTools_ListIteratorOfListOfShape itLSIm(aLSIm); for (; itLSIm.More(); itLSIm.Next()) { if (!myMapShape.Contains(itLSIm.Value())) aHistory.Remove(itLSIm.Value()); } } myHistory->Merge(aHistory); } //======================================================================= // function: SimplifyResult // purpose: Simplifies the result by removing extra edges and vertices // created during operation //======================================================================= void BOPAlgo_RemoveFeatures::SimplifyResult() { if (myShape.IsSame(myInputShape)) return; ShapeUpgrade_UnifySameDomain aSDTool; aSDTool.Initialize(myShape, Standard_True, Standard_True); // Do not allow producing internal edges aSDTool.AllowInternalEdges(Standard_False); // Avoid removal of the input edges and vertices if (myMapShape.IsEmpty()) TopExp::MapShapes(myShape, myMapShape); const Standard_Integer aNbS = myInputsMap.Extent(); for (Standard_Integer i = 1; i <= aNbS; ++i) { if (myMapShape.Contains(myInputsMap(i))) aSDTool.KeepShape(myInputsMap(i)); } // Perform unification aSDTool.Build(); myShape = aSDTool.Shape(); if (HasHistory()) myHistory->Merge(aSDTool.History()); } //======================================================================= // function: PostTreat // purpose: Restore the type of the initial shape //======================================================================= void BOPAlgo_RemoveFeatures::PostTreat() { const TopAbs_ShapeEnum anInputType = myInputShape.ShapeType(); const TopAbs_ShapeEnum aResType = myShape.ShapeType(); if (aResType == anInputType) return; TopExp_Explorer anExpS(myShape, TopAbs_SOLID); if (anInputType == TopAbs_SOLID) { myShape = anExpS.Current(); return; } TopoDS_Shape aRes; if (anInputType == TopAbs_COMPOUND) BRep_Builder().MakeCompound(TopoDS::Compound(aRes)); else BRep_Builder().MakeCompSolid(TopoDS::CompSolid(aRes)); for (; anExpS.More(); anExpS.Next()) BRep_Builder().Add(aRes, anExpS.Current()); myShape = aRes; } //======================================================================= // static methods definition //======================================================================= //======================================================================= // function: MakeRemoved // purpose: Makes the shapes in the list removed in the history. // Keeps the shapes contained in the map. //======================================================================= void MakeRemoved(const TopTools_ListOfShape& theShapes, BRepTools_History& theHistory, const TopTools_IndexedMapOfShape& theKeepShapes) { TopTools_IndexedMapOfShape aShapesMap; TopTools_ListIteratorOfListOfShape it(theShapes); for (; it.More(); it.Next()) TopExp::MapShapes(it.Value(), aShapesMap); const Standard_Integer aNbS = aShapesMap.Extent(); for (Standard_Integer i = 1; i <= aNbS; ++i) { const TopoDS_Shape& aS = aShapesMap(i); if (!theKeepShapes.Contains(aS) && BRepTools_History::IsSupportedType(aS)) { theHistory.Remove(aS); } } } //======================================================================= // function: FindInternals // purpose: Looks for internal shapes inside the face or solid //======================================================================= void FindInternals(const TopoDS_Shape& theS, TopTools_ListOfShape& theLInt) { TopoDS_Iterator itS(theS); for (; itS.More(); itS.Next()) { const TopoDS_Shape& aSS = itS.Value(); if (aSS.Orientation() == TopAbs_INTERNAL) theLInt.Append(aSS); else { TopoDS_Iterator itSS(aSS); for (; itSS.More(); itSS.Next()) { if (itSS.Value().Orientation() == TopAbs_INTERNAL) { theLInt.Append(aSS); break; } } } } } //======================================================================= // function: RemoveInternalWires // purpose: Removes internal wires from the faces //======================================================================= void RemoveInternalWires(const TopTools_ListOfShape& theShapes, TopTools_ListOfShape *theRemoved) { TopTools_ListIteratorOfListOfShape itLS(theShapes); for (; itLS.More(); itLS.Next()) { const TopoDS_Shape& aShape = itLS.Value(); TopExp_Explorer anExpF(aShape, TopAbs_FACE); for (; anExpF.More(); anExpF.Next()) { TopoDS_Face& aF = *(TopoDS_Face*)&anExpF.Current(); TopTools_ListOfShape aLWToRemove; FindInternals(aF, aLWToRemove); if (aLWToRemove.Extent()) { aF.Free(Standard_True); TopTools_ListIteratorOfListOfShape itR(aLWToRemove); for (; itR.More(); itR.Next()) { if (theRemoved) theRemoved->Append(itR.Value()); BRep_Builder().Remove(aF, itR.Value()); } aF.Free(Standard_False); } } } } //======================================================================= // function: GetOriginalFaces // purpose: Get original faces from my face //======================================================================= void GetOriginalFaces(const TopoDS_Shape& theShape, const TopTools_IndexedMapOfShape& theSolids, const TopTools_MapOfShape& theFeatureFacesMap, const TopTools_IndexedDataMapOfShapeListOfShape& theAdjFaces, const Handle(BRepTools_History)& theHistory, TopTools_IndexedMapOfShape& theFacesToBeKept, TopTools_ListOfShape& theInternalShapes, TopTools_MapOfShape& theFacesToCheckOri, TopTools_IndexedMapOfShape& theSolidsToRebuild, TopTools_ListOfShape& theSharedFaces, TopTools_ListOfShape& theUnTouchedSolids) { // Use only solids which has to be reconstructed by the feature. // All other solids should be avoided in the feature removal and added // into result directly. // Update solids after removal of previous features const Standard_Integer aNbSols = theSolids.Extent(); for (Standard_Integer i = 1; i <= aNbSols; ++i) { const TopoDS_Shape& aSol = theSolids(i); const TopTools_ListOfShape& aLFIm = theHistory->Modified(aSol); if (aLFIm.IsEmpty()) theSolidsToRebuild.Add(aSol); else theSolidsToRebuild.Add(aLFIm.First()); } // Splits of the feature faces TopTools_MapOfShape aFeatureFacesSplits; TopTools_MapIteratorOfMapOfShape itM(theFeatureFacesMap); for (; itM.More(); itM.Next()) { const TopoDS_Shape& aF = itM.Value(); const TopTools_ListOfShape& aLFIm = theHistory->Modified(aF); if (aLFIm.IsEmpty()) aFeatureFacesSplits.Add(aF); else { TopTools_ListIteratorOfListOfShape itLFIm(aLFIm); for (; itLFIm.More(); itLFIm.Next()) aFeatureFacesSplits.Add(itLFIm.Value()); } } TopExp_Explorer anExpS(theShape, TopAbs_SOLID); for (; anExpS.More(); anExpS.Next()) { const TopoDS_Shape& aSol = anExpS.Current(); // Check if the solid has to be reconstructed if (!theSolidsToRebuild.Contains(aSol)) { // untouched solid theUnTouchedSolids.Append(aSol); continue; } TopoDS_Iterator itSh(aSol); for (; itSh.More(); itSh.Next()) { const TopoDS_Shape& aSh = itSh.Value(); if (aSh.ShapeType() != TopAbs_SHELL) { theInternalShapes.Append(aSh); continue; } TopoDS_Iterator itF(aSh); for (; itF.More(); itF.Next()) { const TopoDS_Shape& aF = itF.Value(); // Avoid the feature faces if (aFeatureFacesSplits.Contains(aF)) continue; // Avoid the adjacent faces if (theAdjFaces.Contains(aF)) continue; if (aF.Orientation() != TopAbs_INTERNAL) { theFacesToBeKept.Add(aF); if (!theFacesToCheckOri.Add(aF)) { theFacesToCheckOri.Remove(aF); theSharedFaces.Append(aF); } } else theInternalShapes.Append(aSh); } } } } //======================================================================= // function: FindShape // purpose: Find the shape in the other shape //======================================================================= void FindShape(const TopoDS_Shape& theSWhat, const TopoDS_Shape& theSWhere, TopoDS_Shape& theSFound) { TopExp_Explorer anExp(theSWhere, theSWhat.ShapeType()); for (; anExp.More(); anExp.Next()) { const TopoDS_Shape& aS = anExp.Current(); if (aS.IsSame(theSWhat)) { theSFound = aS; break; } } } //======================================================================= // function: GetValidSolids // purpose: Checks the validity of the solids and keeps only valid ones //======================================================================= void GetValidSolids(BOPAlgo_MakerVolume& theMV, const TopTools_MapOfShape& theFacesToCheckOri, const TopTools_ListOfShape& aSharedFaces, const TopoDS_Shape& theOrigFaces, const Standard_Integer theNbSol, TopTools_ListOfShape& theLSRes, TopTools_ListOfShape& theRemovedShapes) { TopExp_Explorer anExpS(theMV.Shape(), TopAbs_SOLID); for (; anExpS.More(); anExpS.Next()) theLSRes.Append(anExpS.Current()); if (theLSRes.Extent() > theNbSol) { // Find Solids filling the holes in the initial shape TopTools_MapOfShape aSolidsToAvoid; TopTools_IndexedDataMapOfShapeListOfShape aFSMap; TopExp::MapShapesAndAncestors(theMV.Shape(), TopAbs_FACE, TopAbs_SOLID, aFSMap); FindExtraShapes(aFSMap, theFacesToCheckOri, theMV, aSolidsToAvoid); TopTools_ListIteratorOfListOfShape itLS(theLSRes); for (; itLS.More(); ) { if (aSolidsToAvoid.Contains(itLS.Value())) theLSRes.Remove(itLS); else itLS.Next(); } } if (theLSRes.Extent() > theNbSol) { // Check if the splits of the adjacent faces split the solids AvoidExtraSharedFaces(theLSRes, aSharedFaces, theMV, theRemovedShapes); } if (theLSRes.Extent() > theNbSol) { // Remove solids containing only the adjacent faces TopTools_MapOfShape anOrigFacesRes; TopExp_Explorer anExpF(theOrigFaces, TopAbs_FACE); for (; anExpF.More(); anExpF.Next()) TakeModified(anExpF.Current(), theMV, anOrigFacesRes); TopTools_ListIteratorOfListOfShape itLS(theLSRes); for (; itLS.More(); ) { anExpF.Init(itLS.Value(), TopAbs_FACE); for (; anExpF.More(); anExpF.Next()) { if (anOrigFacesRes.Contains(anExpF.Current())) break; } if (!anExpF.More()) { theRemovedShapes.Append(itLS.Value()); theLSRes.Remove(itLS); } else itLS.Next(); } } } //======================================================================= // function: FindExtraShape // purpose: Find shapes possibly filling the holes in the original shape //======================================================================= void FindExtraShapes(const TopTools_IndexedDataMapOfShapeListOfShape& theConnectionMap, const TopTools_MapOfShape& theShapesToCheckOri, BOPAlgo_Builder& theBuilder, TopTools_MapOfShape& theShapesToAvoid, TopTools_MapOfShape* theValidShapes) { Handle(IntTools_Context) aCtx = theBuilder.Context(); TopTools_MapOfShape aValidShapes; TopTools_MapOfShape* pValidShapes = theValidShapes ? theValidShapes : &aValidShapes; TopTools_MapIteratorOfMapOfShape itM(theShapesToCheckOri); for (; itM.More(); itM.Next()) { const TopoDS_Shape& aSToCheckOri = itM.Value(); // Check modification of the shape during intersection TopTools_ListOfShape aLSIm; TakeModified(aSToCheckOri, theBuilder, aLSIm); TopTools_ListIteratorOfListOfShape itLSIm(aLSIm); for (; itLSIm.More(); itLSIm.Next()) { const TopoDS_Shape& aSIm = itLSIm.Value(); const TopTools_ListOfShape* pShapesToValidate = theConnectionMap.Seek(aSIm); if (!pShapesToValidate) continue; TopTools_ListIteratorOfListOfShape itSV(*pShapesToValidate); for (; itSV.More(); itSV.Next()) { const TopoDS_Shape& aShapeToValidate = itSV.Value(); if (pValidShapes->Contains(aShapeToValidate)) continue; TopoDS_Face aSInShape; FindShape(aSIm, aShapeToValidate, aSInShape); Standard_Boolean bSameOri = !BOPTools_AlgoTools::IsSplitToReverse(aSInShape, aSToCheckOri, aCtx); if (bSameOri) pValidShapes->Add(aShapeToValidate); else theShapesToAvoid.Add(aShapeToValidate); } } } itM.Initialize(*pValidShapes); for (; itM.More(); itM.Next()) theShapesToAvoid.Remove(itM.Value()); } //======================================================================= // function: AvoidExtraSharedFaces // purpose: Looks for the extra faces splitting the solids //======================================================================= void AvoidExtraSharedFaces(TopTools_ListOfShape& theLSolids, const TopTools_ListOfShape& theLFSharedToAvoid, BOPAlgo_Builder& theBuilder, TopTools_ListOfShape& theExtraFaces) { // Get all splits of shared faces to avoid in the check TopTools_MapOfShape aMFSharedSp; { TopTools_ListOfShape aLFSharedSp; TopTools_ListIteratorOfListOfShape itLFS(theLFSharedToAvoid); for (; itLFS.More(); itLFS.Next()) TakeModified(itLFS.Value(), theBuilder, aMFSharedSp); } TopTools_IndexedDataMapOfShapeListOfShape aFSMap; TopTools_ListIteratorOfListOfShape itLS(theLSolids); for (; itLS.More(); itLS.Next()) TopExp::MapShapesAndAncestors(itLS.Value(), TopAbs_FACE, TopAbs_SOLID, aFSMap); TopTools_ListOfShape anExtraFaces; TopTools_ListOfShape aLFArguments; itLS.Initialize(theLSolids); for (; itLS.More(); itLS.Next()) { const TopoDS_Shape& aSol = itLS.Value(); TopExp_Explorer anExpF(aSol, TopAbs_FACE); for (; anExpF.More(); anExpF.Next()) { const TopoDS_Shape& aF = anExpF.Current(); const TopTools_ListOfShape& aLSol = aFSMap.FindFromKey(aF); if (aLSol.Extent() != 2 || aMFSharedSp.Contains(aF)) aLFArguments.Append(aF); else anExtraFaces.Append(aF); } } if (anExtraFaces.IsEmpty()) return; // Rebuild the solids avoiding the extra faces BOPAlgo_BuilderSolid aBS; aBS.SetAvoidInternalShapes(Standard_True); aBS.SetShapes(aLFArguments); aBS.Perform(); if (aBS.HasErrors()) return; theLSolids = aBS.Areas(); theExtraFaces.Append(anExtraFaces); } //======================================================================= // function: FillSolidsHistory // purpose: Fills the history of solids modifications //======================================================================= void FillSolidsHistory(const TopTools_IndexedMapOfShape& theSolIn, TopTools_ListOfShape& theSolidsOut, const TopTools_IndexedDataMapOfShapeListOfShape& theAdjFaces, BOPAlgo_Builder& theBuilder, BRepTools_History& theSolidsHistory) { const Standard_Integer aNbS = theSolIn.Extent(); for (Standard_Integer i = 1; i <= aNbS; ++i) { const TopoDS_Shape& aSolIn = theSolIn(i); TopoDS_Shape aSolOut; FindSolid(aSolIn, theSolidsOut, theAdjFaces, theBuilder, aSolOut); if (aSolOut.IsNull()) { theSolidsHistory.Remove(aSolIn); continue; } // Check if the solid has really been modified BOPTools_Set aSTIn, aSTOut; aSTIn.Add(aSolIn, TopAbs_FACE); aSTOut.Add(aSolOut, TopAbs_FACE); if (aSTIn.IsEqual(aSTOut)) { // The solids are the same. Replace the resulting solid in the result list // with the initial solid. TopTools_ListIteratorOfListOfShape itLS(theSolidsOut); for (; itLS.More(); itLS.Next()) { if (itLS.Value().IsSame(aSolOut)) { theSolidsOut.InsertBefore(aSolIn, itLS); theSolidsOut.Remove(itLS); break; } } } else { theSolidsHistory.AddModified(aSolIn, aSolOut); } } } //======================================================================= // function: TakeModified // purpose: Stores the modified object into the list //======================================================================= void TakeModified(const TopoDS_Shape& theS, BOPAlgo_Builder& theBuilder, TopTools_ListOfShape& theList) { const TopTools_ListOfShape& aModified = theBuilder.Modified(theS); if (aModified.IsEmpty() && !theBuilder.IsDeleted(theS)) theList.Append(theS); else { TopTools_ListIteratorOfListOfShape itM(aModified); for (; itM.More(); itM.Next()) theList.Append(itM.Value()); } } //======================================================================= // function: TakeModified // purpose: Stores the modified object into the map //======================================================================= void TakeModified(const TopoDS_Shape& theS, BOPAlgo_Builder& theBuilder, TopTools_MapOfShape& theMap) { const TopTools_ListOfShape& aModified = theBuilder.Modified(theS); if (aModified.IsEmpty() && !theBuilder.IsDeleted(theS)) theMap.Add(theS); else { TopTools_ListIteratorOfListOfShape itM(aModified); for (; itM.More(); itM.Next()) theMap.Add(itM.Value()); } } //======================================================================= // function: FindSolid // purpose: Looks for the image of the solid in the list of resulting solids //======================================================================= void FindSolid(const TopoDS_Shape& theSolIn, const TopTools_ListOfShape& theSolidsRes, const TopTools_IndexedDataMapOfShapeListOfShape& theAdjFaces, BOPAlgo_Builder& theBuilder, TopoDS_Shape& theSolOut) { Handle(IntTools_Context) aCtx = theBuilder.Context(); // Take the face in the IN solid, and find it in the OUT list TopExp_Explorer anExpF(theSolIn, TopAbs_FACE); for (; anExpF.More(); anExpF.Next()) { const TopoDS_Shape& aFS = anExpF.Current(); // Images of the face TopTools_MapOfShape aMFSIm; const TopTools_ListOfShape* pLFA = theAdjFaces.Seek(aFS); if (pLFA) { TopTools_ListIteratorOfListOfShape itLFA(*pLFA); for (; itLFA.More(); itLFA.Next()) TakeModified(itLFA.Value(), theBuilder, aMFSIm); } else { TakeModified(aFS, theBuilder, aMFSIm); } // Find any of these faces in the list of solids TopTools_ListIteratorOfListOfShape itLS(theSolidsRes); for (; itLS.More(); itLS.Next()) { const TopoDS_Shape& aSol = itLS.Value(); TopExp_Explorer anExpFOut(aSol, TopAbs_FACE); for (; anExpFOut.More(); anExpFOut.Next()) { const TopoDS_Shape& aF = anExpFOut.Current(); if (aMFSIm.Contains(aF)) { // check orientations if (!BOPTools_AlgoTools::IsSplitToReverse(aF, aFS, aCtx)) { theSolOut = aSol; return; } } } } } }