mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-04-10 18:51:21 +03:00
Update BOP commands to use progress indicator Deleted wrong usage of progress indicator from bop operations Added UserBreak() method to break execution boolean operation if progress indicator is used Added method AnalyzeProgress() to calculate steps of progress indicator Introduce BOPAlgo_ParallelAlgo which has myRange as a field to be used in parallel vector. Provide suitable way of keeping the progress steps of operations. Give meaningful names to progress scopes. Propagate progress indicator into deeper methods of BOA. Add progress indicator to BOPAlgo_BuilderFace and BOPAlgo_WireSplitter, BOPAlgo_BuilderSolid and BOPAlgo_ShellSplitter
1667 lines
55 KiB
C++
1667 lines
55 KiB
C++
// 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 <BOPAlgo_RemoveFeatures.hxx>
|
|
|
|
#include <BOPAlgo_Alerts.hxx>
|
|
#include <BOPAlgo_BOP.hxx>
|
|
#include <BOPAlgo_Builder.hxx>
|
|
#include <BOPAlgo_BuilderSolid.hxx>
|
|
#include <BOPAlgo_MakerVolume.hxx>
|
|
#include <BOPAlgo_Tools.hxx>
|
|
|
|
#include <BOPTools_AlgoTools.hxx>
|
|
#include <BOPTools_Parallel.hxx>
|
|
#include <BOPTools_Set.hxx>
|
|
|
|
#include <Bnd_Box.hxx>
|
|
|
|
#include <BRep_Builder.hxx>
|
|
|
|
#include <BRepBndLib.hxx>
|
|
|
|
#include <BRepLib.hxx>
|
|
|
|
#include <NCollection_Vector.hxx>
|
|
|
|
#include <ShapeUpgrade_UnifySameDomain.hxx>
|
|
|
|
#include <TopAbs_ShapeEnum.hxx>
|
|
|
|
#include <TopExp.hxx>
|
|
#include <TopExp_Explorer.hxx>
|
|
|
|
#include <TopoDS.hxx>
|
|
#include <TopoDS_Compound.hxx>
|
|
#include <TopoDS_Edge.hxx>
|
|
#include <TopoDS_Face.hxx>
|
|
|
|
#include <TopTools_IndexedDataMapOfShapeShape.hxx>
|
|
|
|
|
|
//=======================================================================
|
|
// 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(const Message_ProgressRange& /*theRange*/)
|
|
{
|
|
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
|
|
BOPTools_AlgoTools::TreatCompound(myInputShape, aShapes, &aMFence);
|
|
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<FillGap> VectorOfFillGap;
|
|
|
|
//=======================================================================
|
|
// 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
|
|
BOPTools_Parallel::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 <aFacesToBeKept>
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|