1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-05-16 10:54:53 +03:00
occt/src/BOPAlgo/BOPAlgo_Builder.cxx
akaftasev d03c08988c 0021264: Modeling Algorithms - Progress indicator for Boolean operations
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
2021-09-03 20:19:55 +03:00

844 lines
25 KiB
C++

// Created by: Peter KURNEV
// Copyright (c) 2010-2014 OPEN CASCADE SAS
// Copyright (c) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
// Copyright (c) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, CEDRAT,
// EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This 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_Builder.hxx>
#include <BOPAlgo_Alerts.hxx>
#include <BOPAlgo_BuilderSolid.hxx>
#include <BOPAlgo_PaveFiller.hxx>
#include <BOPAlgo_Tools.hxx>
#include <BOPDS_DS.hxx>
#include <BOPDS_ShapeInfo.hxx>
#include <BOPTools_AlgoTools.hxx>
#include <BRep_Builder.hxx>
#include <IntTools_Context.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Solid.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopTools_MapOfOrientedShape.hxx>
//=======================================================================
//function :
//purpose :
//=======================================================================
BOPAlgo_Builder::BOPAlgo_Builder()
:
BOPAlgo_BuilderShape(),
myArguments(myAllocator),
myMapFence(100, myAllocator),
myPaveFiller(NULL),
myDS(NULL),
myEntryPoint(0),
myImages(100, myAllocator),
myShapesSD(100, myAllocator),
myOrigins(100, myAllocator),
myInParts(100, myAllocator),
myNonDestructive(Standard_False),
myGlue(BOPAlgo_GlueOff),
myCheckInverted(Standard_True)
{
}
//=======================================================================
//function :
//purpose :
//=======================================================================
BOPAlgo_Builder::BOPAlgo_Builder
(const Handle(NCollection_BaseAllocator)& theAllocator)
:
BOPAlgo_BuilderShape(theAllocator),
myArguments(myAllocator),
myMapFence(100, myAllocator),
myPaveFiller(NULL),
myDS(NULL),
myEntryPoint(0),
myImages(100, myAllocator),
myShapesSD(100, myAllocator),
myOrigins(100, myAllocator),
myInParts(100, myAllocator),
myNonDestructive(Standard_False),
myGlue(BOPAlgo_GlueOff),
myCheckInverted(Standard_True)
{
}
//=======================================================================
//function : ~
//purpose :
//=======================================================================
BOPAlgo_Builder::~BOPAlgo_Builder()
{
if (myEntryPoint==1) {
if (myPaveFiller) {
delete myPaveFiller;
myPaveFiller=NULL;
}
}
}
//=======================================================================
//function : Clear
//purpose :
//=======================================================================
void BOPAlgo_Builder::Clear()
{
BOPAlgo_BuilderShape::Clear();
myArguments.Clear();
myMapFence.Clear();
myImages.Clear();
myShapesSD.Clear();
myOrigins.Clear();
myInParts.Clear();
}
//=======================================================================
//function : AddArgument
//purpose :
//=======================================================================
void BOPAlgo_Builder::AddArgument(const TopoDS_Shape& theShape)
{
if (myMapFence.Add(theShape)) {
myArguments.Append(theShape);
}
}
//=======================================================================
//function : SetArguments
//purpose :
//=======================================================================
void BOPAlgo_Builder::SetArguments(const TopTools_ListOfShape& theShapes)
{
TopTools_ListIteratorOfListOfShape aIt;
//
myArguments.Clear();
//
aIt.Initialize(theShapes);
for (; aIt.More(); aIt.Next()) {
const TopoDS_Shape& aS = aIt.Value();
AddArgument(aS);
}
}
//=======================================================================
// function: CheckData
// purpose:
//=======================================================================
void BOPAlgo_Builder::CheckData()
{
Standard_Integer aNb = myArguments.Extent();
if (aNb<2) {
AddError (new BOPAlgo_AlertTooFewArguments); // too few arguments to process
return;
}
//
CheckFiller();
}
//=======================================================================
// function: CheckFiller
// purpose:
//=======================================================================
void BOPAlgo_Builder::CheckFiller()
{
if (!myPaveFiller) {
AddError (new BOPAlgo_AlertNoFiller);
return;
}
GetReport()->Merge (myPaveFiller->GetReport());
}
//=======================================================================
//function : Prepare
//purpose :
//=======================================================================
void BOPAlgo_Builder::Prepare()
{
BRep_Builder aBB;
TopoDS_Compound aC;
//
// 1. myShape is empty compound
aBB.MakeCompound(aC);
myShape=aC;
}
//=======================================================================
//function : Perform
//purpose :
//=======================================================================
void BOPAlgo_Builder::Perform(const Message_ProgressRange& theRange)
{
GetReport()->Clear();
//
if (myEntryPoint==1) {
if (myPaveFiller) {
delete myPaveFiller;
myPaveFiller=NULL;
}
}
//
Handle(NCollection_BaseAllocator) aAllocator=
NCollection_BaseAllocator::CommonBaseAllocator();
//
BOPAlgo_PaveFiller* pPF=new BOPAlgo_PaveFiller(aAllocator);
//
pPF->SetArguments(myArguments);
pPF->SetRunParallel(myRunParallel);
Message_ProgressScope aPS(theRange, "Performing General Fuse operation", 10);
pPF->SetFuzzyValue(myFuzzyValue);
pPF->SetNonDestructive(myNonDestructive);
pPF->SetGlue(myGlue);
pPF->SetUseOBB(myUseOBB);
//
pPF->Perform(aPS.Next(9));
//
myEntryPoint=1;
PerformInternal(*pPF, aPS.Next(1));
}
//=======================================================================
//function : PerformWithFiller
//purpose :
//=======================================================================
void BOPAlgo_Builder::PerformWithFiller(const BOPAlgo_PaveFiller& theFiller, const Message_ProgressRange& theRange)
{
GetReport()->Clear();
myEntryPoint=0;
myNonDestructive = theFiller.NonDestructive();
myFuzzyValue = theFiller.FuzzyValue();
myGlue = theFiller.Glue();
myUseOBB = theFiller.UseOBB();
PerformInternal(theFiller, theRange);
}
//=======================================================================
//function : PerformInternal
//purpose :
//=======================================================================
void BOPAlgo_Builder::PerformInternal(const BOPAlgo_PaveFiller& theFiller, const Message_ProgressRange& theRange)
{
GetReport()->Clear();
//
try {
OCC_CATCH_SIGNALS
PerformInternal1(theFiller, theRange);
}
//
catch (Standard_Failure const&) {
AddError (new BOPAlgo_AlertBuilderFailed);
}
}
//=======================================================================
//function : getNbShapes
//purpose :
//=======================================================================
BOPAlgo_Builder::NbShapes BOPAlgo_Builder::getNbShapes() const
{
NbShapes aCounter;
aCounter.NbVertices() = myDS->ShapesSD().Size();
for (Standard_Integer i = 0; i < myDS->NbSourceShapes(); ++i)
{
const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
switch (aSI.ShapeType())
{
case TopAbs_EDGE:
{
if (myDS->HasPaveBlocks(i))
{
aCounter.NbEdges()++;
}
break;
}
case TopAbs_WIRE:
aCounter.NbWires()++;
break;
case TopAbs_FACE:
{
if (myDS->HasFaceInfo(i))
{
aCounter.NbFaces()++;
}
break;
}
case TopAbs_SHELL:
aCounter.NbShells()++;
break;
case TopAbs_SOLID:
aCounter.NbSolids()++;
break;
case TopAbs_COMPSOLID:
aCounter.NbCompsolids()++;
break;
case TopAbs_COMPOUND:
aCounter.NbCompounds()++;
break;
default: break;
}
}
return aCounter;
}
//=======================================================================
// function: fillPIConstants
// purpose:
//=======================================================================
void BOPAlgo_Builder::fillPIConstants (const Standard_Real theWhole,
BOPAlgo_PISteps& theSteps) const
{
// Fill in the constants:
if (myFillHistory)
{
// for FillHistroty, which takes about 5% of the whole operation
theSteps.SetStep(PIOperation_FillHistory, 0.05 * theWhole);
}
// and for PostTreat, which takes about 3% of the whole operation
theSteps.SetStep(PIOperation_PostTreat, 0.03 * theWhole);
}
//=======================================================================
// function: fillPISteps
// purpose:
//=======================================================================
void BOPAlgo_Builder::fillPISteps (BOPAlgo_PISteps& theSteps) const
{
// Compute the rest of the operations - all depend on the number of sub-shapes of certain type
NbShapes aNbShapes = getNbShapes();
theSteps.SetStep(PIOperation_TreatVertices, aNbShapes.NbVertices());
theSteps.SetStep(PIOperation_TreatEdges, aNbShapes.NbEdges());
theSteps.SetStep(PIOperation_TreatWires, aNbShapes.NbWires());
theSteps.SetStep(PIOperation_TreatFaces, 20 * aNbShapes.NbFaces());
theSteps.SetStep(PIOperation_TreatShells, aNbShapes.NbShells());
theSteps.SetStep(PIOperation_TreatSolids, 50 * aNbShapes.NbSolids());
theSteps.SetStep(PIOperation_TreatCompsolids, aNbShapes.NbCompsolids());
theSteps.SetStep(PIOperation_TreatCompounds, aNbShapes.NbCompounds());
}
//=======================================================================
//function : PerformInternal1
//purpose :
//=======================================================================
void BOPAlgo_Builder::PerformInternal1(const BOPAlgo_PaveFiller& theFiller, const Message_ProgressRange& theRange)
{
myPaveFiller=(BOPAlgo_PaveFiller*)&theFiller;
myDS=myPaveFiller->PDS();
myContext=myPaveFiller->Context();
myFuzzyValue = myPaveFiller->FuzzyValue();
myNonDestructive = myPaveFiller->NonDestructive();
//
Message_ProgressScope aPS(theRange, "Building the result of General Fuse operation", 100);
// 1. CheckData
CheckData();
if (HasErrors()) {
return;
}
//
// 2. Prepare
Prepare();
if (HasErrors()) {
return;
}
//
BOPAlgo_PISteps aSteps(PIOperation_Last);
analyzeProgress(100., aSteps);
// 3. Fill Images
// 3.1 Vertice
FillImagesVertices(aPS.Next(aSteps.GetStep(PIOperation_TreatVertices)));
if (HasErrors()) {
return;
}
//
BuildResult(TopAbs_VERTEX);
if (HasErrors()) {
return;
}
// 3.2 Edges
FillImagesEdges(aPS.Next(aSteps.GetStep(PIOperation_TreatEdges)));
if (HasErrors()) {
return;
}
//
BuildResult(TopAbs_EDGE);
if (HasErrors()) {
return;
}
//
// 3.3 Wires
FillImagesContainers(TopAbs_WIRE, aPS.Next(aSteps.GetStep(PIOperation_TreatWires)));
if (HasErrors()) {
return;
}
//
BuildResult(TopAbs_WIRE);
if (HasErrors()) {
return;
}
// 3.4 Faces
FillImagesFaces(aPS.Next(aSteps.GetStep(PIOperation_TreatFaces)));
if (HasErrors()) {
return;
}
//
BuildResult(TopAbs_FACE);
if (HasErrors()) {
return;
}
// 3.5 Shells
FillImagesContainers(TopAbs_SHELL, aPS.Next(aSteps.GetStep(PIOperation_TreatShells)));
if (HasErrors()) {
return;
}
BuildResult(TopAbs_SHELL);
if (HasErrors()) {
return;
}
// 3.6 Solids
FillImagesSolids(aPS.Next(aSteps.GetStep(PIOperation_TreatSolids)));
if (HasErrors()) {
return;
}
BuildResult(TopAbs_SOLID);
if (HasErrors()) {
return;
}
// 3.7 CompSolids
FillImagesContainers(TopAbs_COMPSOLID, aPS.Next(aSteps.GetStep(PIOperation_TreatCompsolids)));
if (HasErrors()) {
return;
}
BuildResult(TopAbs_COMPSOLID);
if (HasErrors()) {
return;
}
// 3.8 Compounds
FillImagesCompounds(aPS.Next(aSteps.GetStep(PIOperation_TreatCompounds)));
if (HasErrors()) {
return;
}
BuildResult(TopAbs_COMPOUND);
if (HasErrors()) {
return;
}
//
// 4 History
PrepareHistory(aPS.Next(aSteps.GetStep(PIOperation_FillHistory)));
if (HasErrors()) {
return;
}
//
// 5 Post-treatment
PostTreat(aPS.Next(aSteps.GetStep(PIOperation_PostTreat)));
}
//=======================================================================
//function : PostTreat
//purpose :
//=======================================================================
void BOPAlgo_Builder::PostTreat(const Message_ProgressRange& theRange)
{
Standard_Integer i, aNbS;
TopAbs_ShapeEnum aType;
TopTools_IndexedMapOfShape aMA;
if (myPaveFiller->NonDestructive()) {
// MapToAvoid
aNbS=myDS->NbSourceShapes();
for (i=0; i<aNbS; ++i) {
const BOPDS_ShapeInfo& aSI=myDS->ShapeInfo(i);
aType=aSI.ShapeType();
if (aType==TopAbs_VERTEX ||
aType==TopAbs_EDGE||
aType==TopAbs_FACE) {
const TopoDS_Shape& aS=aSI.Shape();
aMA.Add(aS);
}
}
}
//
Message_ProgressScope aPS(theRange, "Post treatment of result shape", 2);
BOPTools_AlgoTools::CorrectTolerances(myShape, aMA, 0.05, myRunParallel);
aPS.Next();
BOPTools_AlgoTools::CorrectShapeTolerances(myShape, aMA, myRunParallel);
}
//=======================================================================
//function : BuildBOP
//purpose :
//=======================================================================
void BOPAlgo_Builder::BuildBOP(const TopTools_ListOfShape& theObjects,
const TopAbs_State theObjState,
const TopTools_ListOfShape& theTools,
const TopAbs_State theToolsState,
const Message_ProgressRange& theRange,
Handle(Message_Report) theReport)
{
if (HasErrors())
return;
// Report for the method
Handle(Message_Report) aReport = theReport.IsNull() ? myReport : theReport;
if (myArguments.IsEmpty() || myShape.IsNull())
{
aReport->AddAlert(Message_Fail, new BOPAlgo_AlertBuilderFailed());
return;
}
// Check the input data
if ((theObjState != TopAbs_IN && theObjState != TopAbs_OUT) ||
(theToolsState != TopAbs_IN && theToolsState != TopAbs_OUT))
{
aReport->AddAlert(Message_Fail, new BOPAlgo_AlertBOPNotSet());
return;
}
// Check input shapes
Standard_Boolean hasObjects = !theObjects.IsEmpty();
Standard_Boolean hasTools = !theTools .IsEmpty();
if (!hasObjects && !hasTools)
{
aReport->AddAlert(Message_Fail, new BOPAlgo_AlertTooFewArguments());
return;
}
// Check that all input solids are from the arguments
for (Standard_Integer i = 0; i < 2; ++i)
{
const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
TopTools_ListOfShape::Iterator itLS(aList);
for (; itLS.More(); itLS.Next())
{
const TopoDS_Shape& aS = itLS.Value();
// Check if the shape belongs to the arguments of operation
if (myDS->Index(aS) < 0)
{
aReport->AddAlert(Message_Fail, new BOPAlgo_AlertUnknownShape(aS));
return;
}
// Check if the shape is a solid or collection of them
if (aS.ShapeType() != TopAbs_SOLID)
{
TopTools_ListOfShape aLS;
TopTools_MapOfShape aMFence;
BOPTools_AlgoTools::TreatCompound(aS, aLS, &aMFence);
TopTools_ListOfShape::Iterator it(aLS);
for (; it.More(); it.Next())
{
const TopoDS_Shape& aSx = it.Value();
if (aSx.ShapeType() != TopAbs_SOLID &&
aSx.ShapeType() != TopAbs_COMPSOLID)
{
aReport->AddAlert(Message_Fail, new BOPAlgo_AlertUnsupportedType(aS));
return;
}
}
}
}
}
// Classification of the faces relatively solids has been made
// on the stage of Solids splitting. All results are saved into
// myInParts map, which connects the solids with its IN faces from
// other arguments. All faces not contained in the list of IN faces
// will be considered as OUT.
// Prepare the maps of splits of solids faces with orientations
TopTools_IndexedMapOfOrientedShape aMObjFacesOri, aMToolFacesOri;
// Prepare the maps of splits of solids faces
TopTools_IndexedMapOfShape aMObjFaces, aMToolFaces;
// Copy the list of IN faces of the solids into map
TopTools_MapOfShape anINObjects, anINTools;
for (Standard_Integer i = 0; i < 2; ++i)
{
const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
TopTools_IndexedMapOfOrientedShape& aMapOri = !i ? aMObjFacesOri : aMToolFacesOri;
TopTools_IndexedMapOfShape& aMap = !i ? aMObjFaces : aMToolFaces;
TopTools_ListOfShape::Iterator itLS(aList);
for (; itLS.More(); itLS.Next())
{
const TopoDS_Shape& aShape = itLS.Value();
TopExp_Explorer expS(aShape, TopAbs_SOLID);
for (; expS.More(); expS.Next())
{
const TopoDS_Shape& aS = expS.Current();
TopExp_Explorer expF(aS, TopAbs_FACE);
for (; expF.More(); expF.Next())
{
const TopoDS_Shape& aF = expF.Current();
if (aF.Orientation() != TopAbs_FORWARD &&
aF.Orientation() != TopAbs_REVERSED)
continue;
const TopTools_ListOfShape* pLFIm = myImages.Seek(aF);
if (pLFIm)
{
TopTools_ListOfShape::Iterator itLFIm(*pLFIm);
for (; itLFIm.More(); itLFIm.Next())
{
TopoDS_Face aFIm = TopoDS::Face(itLFIm.Value());
if (BOPTools_AlgoTools::IsSplitToReverse(aFIm, aF, myContext))
aFIm.Reverse();
aMapOri.Add(aFIm);
aMap.Add(aFIm);
}
}
else
{
aMapOri.Add(aF);
aMap.Add(aF);
}
}
// Copy the list of IN faces into a map
const TopTools_ListOfShape* pLFIN = myInParts.Seek(aS);
if (pLFIN)
{
TopTools_MapOfShape& anINMap = !i ? anINObjects : anINTools;
TopTools_ListOfShape::Iterator itLFIn(*pLFIN);
for (; itLFIn.More(); itLFIn.Next())
anINMap.Add(itLFIn.Value());
}
}
}
}
// Now we need to select all faces which will participate in
// building of the resulting solids. The final set of faces
// depends on the given states for the groups.
Standard_Boolean isObjectsIN = (theObjState == TopAbs_IN),
isToolsIN = (theToolsState == TopAbs_IN);
// Shortcuts
Standard_Boolean bAvoidIN = (!isObjectsIN && !isToolsIN), // avoid all in faces
bAvoidINforBoth = (isObjectsIN != isToolsIN); // avoid faces IN for both groups
// Choose which SD faces are needed to be taken - equally or differently oriented faces
Standard_Boolean isSameOriNeeded = (theObjState == theToolsState);
// Resulting faces
TopTools_IndexedMapOfOrientedShape aMResFacesOri;
TopTools_MapOfShape aMResFacesFence;
// Fence map
TopTools_MapOfShape aMFence, aMFToAvoid;
// Oriented fence map
TopTools_MapOfOrientedShape aMFenceOri;
for (Standard_Integer i = 0; i < 2; ++i)
{
const TopTools_IndexedMapOfOrientedShape& aMap = !i ? aMObjFacesOri : aMToolFacesOri;
const TopTools_IndexedMapOfShape& anOppositeMap = !i ? aMToolFaces : aMObjFaces;
const TopTools_MapOfShape& anINMap = !i ? anINObjects : anINTools;
const TopTools_MapOfShape& anOppositeINMap = !i ? anINTools : anINObjects;
const Standard_Boolean bTakeIN = !i ? isObjectsIN : isToolsIN;
const Standard_Integer aNbF = aMap.Extent();
for (Standard_Integer j = 1; j <= aNbF; ++j)
{
TopoDS_Shape aFIm = aMap(j);
Standard_Boolean isIN = anINMap.Contains(aFIm);
Standard_Boolean isINOpposite = anOppositeINMap.Contains(aFIm);
// Filtering for FUSE - avoid any IN faces
if (bAvoidIN && (isIN || isINOpposite))
continue;
// Filtering for CUT - avoid faces IN for both groups
if (bAvoidINforBoth && isIN && isINOpposite)
continue;
// Treatment of SD faces
if (!aMFence.Add(aFIm))
{
if (!anOppositeMap.Contains(aFIm))
{
// The face belongs to only one group
if (bTakeIN != isSameOriNeeded)
aMFToAvoid.Add(aFIm);
}
else
{
// The face belongs to both groups.
// Using its orientation decide if it is needed in the result or not.
Standard_Boolean isSameOri = !aMFenceOri.Add(aFIm);
if (isSameOriNeeded == isSameOri)
{
// Take the shape without classification
if (aMResFacesFence.Add(aFIm))
aMResFacesOri.Add(aFIm);
}
else
// Remove the face
aMFToAvoid.Add(aFIm);
continue;
}
}
if (!aMFenceOri.Add(aFIm))
continue;
if (bTakeIN == isINOpposite)
{
if (isIN)
{
aMResFacesOri.Add(aFIm);
aMResFacesOri.Add(aFIm.Reversed());
}
else if (bTakeIN && !isSameOriNeeded)
aMResFacesOri.Add(aFIm.Reversed());
else
aMResFacesOri.Add(aFIm);
aMResFacesFence.Add(aFIm);
}
}
}
// Remove the faces which has to be avoided
TopTools_ListOfShape aResFaces;
const Standard_Integer aNbRF = aMResFacesOri.Extent();
for (Standard_Integer i = 1; i <= aNbRF; ++i)
{
const TopoDS_Shape& aRF = aMResFacesOri(i);
if (!aMFToAvoid.Contains(aRF))
aResFaces.Append(aRF);
}
Message_ProgressScope aPS(theRange, NULL, 2);
BRep_Builder aBB;
// Try to build closed solids from the faces
BOPAlgo_BuilderSolid aBS;
aBS.SetShapes(aResFaces);
aBS.SetRunParallel(myRunParallel);
aBS.SetContext(myContext);
aBS.SetFuzzyValue(myFuzzyValue);
aBS.Perform(aPS.Next());
// Resulting solids
TopTools_ListOfShape aResSolids;
aMFence.Clear();
if (!aBS.HasErrors())
{
// If any, add solids into resulting compound
TopTools_ListIteratorOfListOfShape itA(aBS.Areas());
for (; itA.More(); itA.Next())
{
const TopoDS_Shape& aSolid = itA.Value();
// The solid must contain at least one face
// from either of objects or tools
TopExp_Explorer expF(aSolid, TopAbs_FACE);
for (; expF.More(); expF.Next())
{
const TopoDS_Shape& aF = expF.Current();
if (aMObjFacesOri.Contains(aF) || aMToolFacesOri.Contains(aF))
break;
}
if (expF.More())
{
aResSolids.Append(aSolid);
TopExp::MapShapes(aSolid, aMFence);
}
}
}
else
{
return;
}
// Collect unused faces
TopoDS_Compound anUnUsedFaces;
aBB.MakeCompound(anUnUsedFaces);
TopTools_ListOfShape::Iterator itLF(aResFaces);
for (; itLF.More(); itLF.Next())
{
if (aMFence.Add(itLF.Value()))
aBB.Add(anUnUsedFaces, itLF.Value());
}
// Build blocks from the unused faces
TopTools_ListOfShape aLCB;
BOPTools_AlgoTools::MakeConnexityBlocks(anUnUsedFaces, TopAbs_EDGE, TopAbs_FACE, aLCB);
// Build solid from each block
TopTools_ListIteratorOfListOfShape itCB(aLCB);
for (; itCB.More(); itCB.Next())
{
const TopoDS_Shape& aCB = itCB.Value();
TopoDS_Shell aShell;
aBB.MakeShell(aShell);
// Add faces of the block to the shell
TopExp_Explorer anExpF(aCB, TopAbs_FACE);
for (; anExpF.More(); anExpF.Next())
aBB.Add(aShell, TopoDS::Face(anExpF.Current()));
BOPTools_AlgoTools::OrientFacesOnShell(aShell);
// Make solid out of the shell
TopoDS_Solid aSolid;
aBB.MakeSolid(aSolid);
aBB.Add(aSolid, aShell);
// Add new solid to result
aResSolids.Append(aSolid);
}
if (!bAvoidIN)
{
// Fill solids with internal parts coming with the solids
TopTools_ListOfShape anInParts;
for (Standard_Integer i = 0; i < 2; ++i)
{
const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
TopTools_ListOfShape::Iterator itLS(aList);
for (; itLS.More(); itLS.Next())
{
TopExp_Explorer expS(itLS.Value(), TopAbs_SOLID);
for (; expS.More(); expS.Next())
{
const TopoDS_Shape& aS = expS.Current(); // Solid
for (TopoDS_Iterator it(aS); it.More(); it.Next())
{
const TopoDS_Shape& aSInt = it.Value();
if (aSInt.Orientation() == TopAbs_INTERNAL)
anInParts.Append(aSInt); // vertex or edge
else
{
// shell treatment
TopoDS_Iterator itInt(aSInt);
if (itInt.More() && itInt.Value().Orientation() == TopAbs_INTERNAL)
anInParts.Append(aSInt);
}
}
}
}
}
BOPAlgo_Tools::FillInternals(aResSolids, anInParts, myImages, myContext);
}
// Combine solids into compound
TopoDS_Shape aResult;
aBB.MakeCompound(TopoDS::Compound(aResult));
TopTools_ListOfShape::Iterator itLS(aResSolids);
for (; itLS.More(); itLS.Next())
aBB.Add(aResult, itLS.Value());
myShape = aResult;
PrepareHistory(aPS.Next());
}