1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-04 18:06:22 +03:00
occt/src/BOPAlgo/BOPAlgo_RemoveFeatures.cxx
2019-03-31 23:39:50 +03:00

1673 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()
{
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<FillGap> VectorOfFillGap;
typedef BOPTools_Functor <FillGap, VectorOfFillGap> FillGapFunctor;
typedef BOPTools_Cnt <FillGapFunctor, VectorOfFillGap> 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 <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;
}
}
}
}
}
}