1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-03 17:56:21 +03:00
occt/src/BOPAlgo/BOPAlgo_BOP.cxx
emv 77a11d3df1 0028189: Result of Boolean operation is non-manifold wire
1. The result of Boolean operation on the arguments of collection type, containers WIRE/SHELL/COMPSOLID, is also a collection.
The containers of type WIRE included into result should now also (as the SHELLs) have coherent orientation of its sub-shapes.
For that the new method has been implemented (BOPTools_AlgoTools::OrientEdgesOnWire(TopoDS_Shape&)) which reorients edges for correct ordering.
The duplicating containers, i.e. containers with the contents completely included in other containers, are now avoided in the result of BOP.
2. The result of Fuse operation on Compsolids is now also will be Compsolid.
3. Documentation has been updated.
4. New test cases for the issue.
5. Adjusting test cases to current behavior.

Correction of test case bugs/modalg_4/bug726_2 according to the new behavior
2016-12-29 18:32:44 +03:00

1353 lines
34 KiB
C++

// Created by: Peter KURNEV
// Copyright (c) 1999-2014 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_BOP.hxx>
#include <BOPAlgo_BuilderSolid.hxx>
#include <BOPAlgo_PaveFiller.hxx>
#include <BOPCol_DataMapOfShapeShape.hxx>
#include <BOPCol_IndexedDataMapOfShapeListOfShape.hxx>
#include <BOPCol_IndexedMapOfShape.hxx>
#include <BOPCol_ListOfShape.hxx>
#include <BOPCol_MapOfShape.hxx>
#include <BOPDS_DS.hxx>
#include <BOPTools.hxx>
#include <BOPTools_AlgoTools.hxx>
#include <BOPTools_AlgoTools3D.hxx>
#include <BOPTools_Set.hxx>
#include <BOPTools_SetMapHasher.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <NCollection_DataMap.hxx>
#include <TopAbs_ShapeEnum.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopoDS_Shape.hxx>
typedef NCollection_IndexedDataMap
<BOPTools_Set,
TopoDS_Shape,
BOPTools_SetMapHasher> BOPTools_IndexedDataMapOfSetShape;
//
static
TopAbs_ShapeEnum TypeToExplore(const Standard_Integer theDim);
//
static
void CollectContainers(const TopoDS_Shape& theS,
BOPCol_ListOfShape& theLSC);
//
static
void RemoveDuplicates(BOPCol_ListOfShape& theContainers);
//
static
void RemoveDuplicates(BOPCol_ListOfShape& theContainers,
const TopAbs_ShapeEnum theType);
//
static
Standard_Integer NbCommonItemsInMap(const BOPCol_MapOfShape& theM1,
const BOPCol_MapOfShape& theM2);
//=======================================================================
//function :
//purpose :
//=======================================================================
BOPAlgo_BOP::BOPAlgo_BOP()
:
BOPAlgo_Builder(),
myTools(myAllocator),
myMapTools(100, myAllocator)
{
Clear();
}
//=======================================================================
//function :
//purpose :
//=======================================================================
BOPAlgo_BOP::BOPAlgo_BOP
(const Handle(NCollection_BaseAllocator)& theAllocator)
:
BOPAlgo_Builder(theAllocator),
myTools(myAllocator),
myMapTools(100, myAllocator)
{
Clear();
}
//=======================================================================
//function : ~
//purpose :
//=======================================================================
BOPAlgo_BOP::~BOPAlgo_BOP()
{
}
//=======================================================================
//function : Clear
//purpose :
//=======================================================================
void BOPAlgo_BOP::Clear()
{
myOperation=BOPAlgo_UNKNOWN;
myTools.Clear();
myMapTools.Clear();
myDims[0]=-1;
myDims[1]=-1;
//
BOPAlgo_Builder::Clear();
}
//=======================================================================
//function : SetOperation
//purpose :
//=======================================================================
void BOPAlgo_BOP::SetOperation(const BOPAlgo_Operation theOperation)
{
myOperation=theOperation;
}
//=======================================================================
//function : Operation
//purpose :
//=======================================================================
BOPAlgo_Operation BOPAlgo_BOP::Operation()const
{
return myOperation;
}
//=======================================================================
//function : AddTool
//purpose :
//=======================================================================
void BOPAlgo_BOP::AddTool(const TopoDS_Shape& theShape)
{
if (myMapTools.Add(theShape)) {
myTools.Append(theShape);
}
}
//=======================================================================
//function : SetTools
//purpose :
//=======================================================================
void BOPAlgo_BOP::SetTools(const BOPCol_ListOfShape& theShapes)
{
BOPCol_ListIteratorOfListOfShape aIt;
//
myTools.Clear();
aIt.Initialize(theShapes);
for (; aIt.More(); aIt.Next()) {
const TopoDS_Shape& aS = aIt.Value();
AddTool(aS);
}
}
//=======================================================================
//function : CheckData
//purpose :
//=======================================================================
void BOPAlgo_BOP::CheckData()
{
Standard_Integer i, j, iDim, aNbArgs, aNbTools;
Standard_Boolean bFlag, bFuse;
BOPCol_ListIteratorOfListOfShape aItLS;
//
myErrorStatus=0;
//
if (!(myOperation==BOPAlgo_COMMON ||
myOperation==BOPAlgo_FUSE ||
myOperation==BOPAlgo_CUT||
myOperation==BOPAlgo_CUT21)) {
// non-licit operation
myErrorStatus=14;
return;
}
//
aNbArgs=myArguments.Extent();
if (!aNbArgs) {
// invalid number of Arguments
myErrorStatus=100;
return;
}
//
aNbTools=myTools.Extent();
if (!aNbTools) {
// invalid number of Tools
myErrorStatus=100;
return;
}
//
if (!myPaveFiller) {
myErrorStatus=101;
return;
}
//
myErrorStatus=myPaveFiller->ErrorStatus();
if (myErrorStatus) {
return;
}
//
bFuse = (myOperation == BOPAlgo_FUSE);
//
// The rules for different types of operations are the following:
// 1. FUSE: All arguments and tools should have the same dimension;
// 2. CUT: The MAXIMAL dimension of the ARGUMENTS should be less
// or equal to the MINIMAL dimension of the TOOLS;
// 3. CUT21: The MINIMAL dimension of ARGUMENTS should be grater
// or equal to the MAXIMAL dimension of the TOOLS;
// 4. COMMON: The arguments and tools could have any dimensions.
//
Standard_Integer iDimMin[2], iDimMax[2];
//
for (i=0; i<2; ++i) {
const BOPCol_ListOfShape& aLS=(!i)? myArguments : myTools;
aItLS.Initialize(aLS);
for (j=0; aItLS.More(); aItLS.Next(), ++j) {
const TopoDS_Shape& aS=aItLS.Value();
bFlag=BOPTools_AlgoTools3D::IsEmptyShape(aS);
if(bFlag) {
myWarningStatus=2;
}
//
iDim=BOPTools_AlgoTools::Dimension(aS);
if (iDim<0) {
// non-homogenious argument
myErrorStatus=13;
return;
}
//
if (!j) {
iDimMin[i] = iDim;
iDimMax[i] = iDim;
continue;
}
//
if (iDim < iDimMin[i]) {
iDimMin[i] = iDim;
}
else if (iDim > iDimMax[i]) {
iDimMax[i] = iDim;
}
//
if (bFuse && (iDimMin[i] != iDimMax[i])) {
// non-homogenious argument
myErrorStatus=13;
return;
}
}
}
//
if (((myOperation == BOPAlgo_FUSE) && (iDimMax[0] != iDimMax[1])) ||
((myOperation == BOPAlgo_CUT) && (iDimMax[0] > iDimMin[1])) ||
((myOperation == BOPAlgo_CUT21) && (iDimMin[0] < iDimMax[1])) ) {
// non-licit operation for the arguments
myErrorStatus=14;
return;
}
//
myDims[0] = iDimMin[0];
myDims[1] = iDimMin[1];
}
//=======================================================================
//function : Prepare
//purpose :
//=======================================================================
void BOPAlgo_BOP::Prepare()
{
//
BOPAlgo_Builder::Prepare();
//
if(myWarningStatus == 2) {
Standard_Integer i;
BRep_Builder aBB;
BOPCol_ListIteratorOfListOfShape aItLS;
//
switch(myOperation) {
case BOPAlgo_FUSE: {
for (i=0; i<2; ++i) {
const BOPCol_ListOfShape& aLS=(!i)? myArguments : myTools;
aItLS.Initialize(aLS);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aS=aItLS.Value();
aBB.Add(myShape, aS);
}
}
}
break;
//
case BOPAlgo_CUT: {
aItLS.Initialize(myArguments);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aS=aItLS.Value();
if(!BOPTools_AlgoTools3D::IsEmptyShape(aS)) {
aBB.Add(myShape, aS);
}
}
}
break;
case BOPAlgo_CUT21: {
aItLS.Initialize(myTools);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aS=aItLS.Value();
if(!BOPTools_AlgoTools3D::IsEmptyShape(aS)) {
aBB.Add(myShape, aS);
}
}
}
break;
//
default:
break;
}
}
}
//=======================================================================
//function : BuildResult
//purpose :
//=======================================================================
void BOPAlgo_BOP::BuildResult(const TopAbs_ShapeEnum theType)
{
TopAbs_ShapeEnum aType;
BRep_Builder aBB;
BOPCol_MapOfShape aM;
BOPCol_ListIteratorOfListOfShape aIt, aItIm;
//
myErrorStatus=0;
//
const BOPCol_ListOfShape& aLA=myDS->Arguments();
aIt.Initialize(aLA);
for (; aIt.More(); aIt.Next()) {
const TopoDS_Shape& aS=aIt.Value();
aType=aS.ShapeType();
if (aType==theType) {
if (myImages.IsBound(aS)){
const BOPCol_ListOfShape& aLSIm=myImages.Find(aS);
aItIm.Initialize(aLSIm);
for (; aItIm.More(); aItIm.Next()) {
const TopoDS_Shape& aSIm=aItIm.Value();
if (aM.Add(aSIm)) {
aBB.Add(myShape, aSIm);
}
}
}
else {
if (aM.Add(aS)) {
aBB.Add(myShape, aS);
}
}
}
}
}
//=======================================================================
//function : Perform
//purpose :
//=======================================================================
void BOPAlgo_BOP::Perform()
{
Handle(NCollection_BaseAllocator) aAllocator;
BOPAlgo_PaveFiller* pPF;
BOPCol_ListIteratorOfListOfShape aItLS;
//
myErrorStatus=0;
//
if (myEntryPoint==1) {
if (myPaveFiller) {
delete myPaveFiller;
myPaveFiller=NULL;
}
}
//
aAllocator=
NCollection_BaseAllocator::CommonBaseAllocator();
BOPCol_ListOfShape aLS(aAllocator);
//
aItLS.Initialize(myArguments);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aS=aItLS.Value();
aLS.Append(aS);
}
//
aItLS.Initialize(myTools);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aS=aItLS.Value();
aLS.Append(aS);
}
//
pPF=new BOPAlgo_PaveFiller(aAllocator);
pPF->SetArguments(aLS);
pPF->SetRunParallel(myRunParallel);
pPF->SetProgressIndicator(myProgressIndicator);
pPF->SetFuzzyValue(myFuzzyValue);
pPF->SetNonDestructive(myNonDestructive);
pPF->SetGlue(myGlue);
//
pPF->Perform();
//
myEntryPoint=1;
PerformInternal(*pPF);
}
//=======================================================================
//function : PerformInternal1
//purpose :
//=======================================================================
void BOPAlgo_BOP::PerformInternal1(const BOPAlgo_PaveFiller& theFiller)
{
myErrorStatus=0;
myWarningStatus=0;
//
myPaveFiller=(BOPAlgo_PaveFiller*)&theFiller;
myDS=myPaveFiller->PDS();
myContext=myPaveFiller->Context();
myFuzzyValue = myPaveFiller->FuzzyValue();
myNonDestructive = myPaveFiller->NonDestructive();
//
// 1. CheckData
CheckData();
if (myErrorStatus && !myWarningStatus) {
return;
}
//
// 2. Prepare
Prepare();
if (myErrorStatus) {
return;
}
//
if(myWarningStatus == 2) {
return;
}
// 3. Fill Images
// 3.1 Vertices
FillImagesVertices();
if (myErrorStatus) {
return;
}
//
BuildResult(TopAbs_VERTEX);
if (myErrorStatus) {
return;
}
// 3.2 Edges
FillImagesEdges();
if (myErrorStatus) {
return;
}
//
BuildResult(TopAbs_EDGE);
if (myErrorStatus) {
return;
}
//
// 3.3 Wires
FillImagesContainers(TopAbs_WIRE);
if (myErrorStatus) {
return;
}
//
BuildResult(TopAbs_WIRE);
if (myErrorStatus) {
return;
}
//
// 3.4 Faces
FillImagesFaces();
if (myErrorStatus) {
return;
}
BuildResult(TopAbs_FACE);
if (myErrorStatus) {
return;
}
//
// 3.5 Shells
FillImagesContainers(TopAbs_SHELL);
if (myErrorStatus) {
return;
}
//
BuildResult(TopAbs_SHELL);
if (myErrorStatus) {
return;
}
//
// 3.6 Solids
FillImagesSolids();
if (myErrorStatus) {
return;
}
//
BuildResult(TopAbs_SOLID);
if (myErrorStatus) {
return;
}
//
// 3.7 CompSolids
FillImagesContainers(TopAbs_COMPSOLID);
if (myErrorStatus) {
return;
}
//
BuildResult(TopAbs_COMPSOLID);
if (myErrorStatus) {
return;
}
//
// 3.8 Compounds
FillImagesCompounds();
if (myErrorStatus) {
return;
}
//
BuildResult(TopAbs_COMPOUND);
if (myErrorStatus) {
return;
}
//
// 4.BuildShape;
BuildShape();
if (myErrorStatus) {
return;
}
//
// 5.History
PrepareHistory();
//
// 6 Post-treatment
PostTreat();
}
//=======================================================================
//function : BuildRC
//purpose :
//=======================================================================
void BOPAlgo_BOP::BuildRC()
{
TopAbs_ShapeEnum aType;
TopoDS_Compound aC;
BRep_Builder aBB;
//
myErrorStatus = 0;
//
aBB.MakeCompound(aC);
//
// A. Fuse
if (myOperation == BOPAlgo_FUSE) {
BOPCol_MapOfShape aMFence;
aType = TypeToExplore(myDims[0]);
TopExp_Explorer aExp(myShape, aType);
for (; aExp.More(); aExp.Next()) {
const TopoDS_Shape& aS = aExp.Current();
if (aMFence.Add(aS)) {
aBB.Add(aC, aS);
}
}
myRC = aC;
return;
}
//
// B. Common, Cut, Cut21
//
Standard_Integer i, j, aNb, iDim;
Standard_Boolean bCheckEdges, bContains, bCut21, bCommon;
BOPCol_IndexedMapOfShape aMArgs, aMTools;
BOPCol_IndexedMapOfShape aMArgsIm, aMToolsIm;
BOPCol_ListIteratorOfListOfShape aItLS;
//
for (i = 0; i < 2; ++i) {
const BOPCol_ListOfShape& aLS = !i ? myArguments : myTools;
BOPCol_IndexedMapOfShape& aMS = !i ? aMArgs : aMTools;
aItLS.Initialize(aLS);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aS = aItLS.Value();
iDim = BOPTools_AlgoTools::Dimension(aS);
aType = TypeToExplore(iDim);
BOPTools::MapShapes(aS, aType, aMS);
}
}
//
bCheckEdges = Standard_False;
//
for (i = 0; i < 2; ++i) {
const BOPCol_IndexedMapOfShape& aMS = !i ? aMArgs : aMTools;
BOPCol_IndexedMapOfShape& aMSIm = !i ? aMArgsIm : aMToolsIm;
//
aNb = aMS.Extent();
for (j = 1; j <= aNb; ++j) {
const TopoDS_Shape& aS = aMS(j);
aType = aS.ShapeType();
if (aType == TopAbs_EDGE) {
const TopoDS_Edge& aE = *(TopoDS_Edge*)&aS;
bCheckEdges = Standard_True;
if (BRep_Tool::Degenerated(aE)) {
continue;
}
}
//
if (myImages.IsBound(aS)) {
const BOPCol_ListOfShape& aLSIm = myImages.Find(aS);
aItLS.Initialize(aLSIm);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aSIm = aItLS.Value();
aMSIm.Add(aSIm);
}
}
else {
aMSIm.Add(aS);
}
}
}
//
// compare the maps and make the result
//
Standard_Integer iDimMin, iDimMax;
//
iDimMin = Min(myDims[0], myDims[1]);
bCommon = (myOperation == BOPAlgo_COMMON);
bCut21 = (myOperation == BOPAlgo_CUT21);
//
const BOPCol_IndexedMapOfShape& aMIt = bCut21 ? aMToolsIm : aMArgsIm;
const BOPCol_IndexedMapOfShape& aMCheck = bCut21 ? aMArgsIm : aMToolsIm;
//
BOPCol_IndexedMapOfShape aMCheckExp, aMItExp;
//
if (bCommon) {
aNb = aMIt.Extent();
for (i = 1; i <= aNb; ++i) {
const TopoDS_Shape& aS = aMIt(i);
iDimMax = BOPTools_AlgoTools::Dimension(aS);
for (iDim = iDimMin; iDim < iDimMax; ++iDim) {
aType = TypeToExplore(iDim);
BOPTools::MapShapes(aS, aType, aMItExp);
}
aMItExp.Add(aS);
}
}
else {
aMItExp = aMIt;
}
//
aNb = aMCheck.Extent();
for (i = 1; i <= aNb; ++i) {
const TopoDS_Shape& aS = aMCheck(i);
iDimMax = BOPTools_AlgoTools::Dimension(aS);
for (iDim = iDimMin; iDim < iDimMax; ++iDim) {
aType = TypeToExplore(iDim);
BOPTools::MapShapes(aS, aType, aMCheckExp);
}
aMCheckExp.Add(aS);
}
//
aNb = aMItExp.Extent();
for (i = 1; i <= aNb; ++i) {
const TopoDS_Shape& aS = aMItExp(i);
//
bContains = aMCheckExp.Contains(aS);
if (bCommon) {
if (bContains) {
aBB.Add(aC, aS);
}
}
else {
if (!bContains) {
aBB.Add(aC, aS);
}
}
}
//
// filter result for COMMON operation
if (bCommon) {
BOPCol_MapOfShape aMFence;
TopExp_Explorer aExp;
TopoDS_Compound aCx;
aBB.MakeCompound(aCx);
//
for (iDim = 3; iDim >= iDimMin; --iDim) {
aType = TypeToExplore(iDim);
aExp.Init(aC, aType);
for (; aExp.More(); aExp.Next()) {
const TopoDS_Shape& aS = aExp.Current();
if (aMFence.Add(aS)) {
aBB.Add(aCx, aS);
BOPTools::MapShapes(aS, aMFence);
}
}
}
aC = aCx;
}
//
if (!bCheckEdges) {
myRC = aC;
return;
}
//
// The squats around degenerated edges
Standard_Integer nVD;
BOPCol_IndexedMapOfShape aMVC;
//
// 1. Vertices of aC
BOPTools::MapShapes(aC, TopAbs_VERTEX, aMVC);
//
// 2. DE candidates
aNb = myDS->NbSourceShapes();
for (i = 0; i < aNb; ++i) {
const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
aType = aSI.ShapeType();
if (aType != TopAbs_EDGE) {
continue;
}
//
const TopoDS_Edge& aE = *((TopoDS_Edge*)&aSI.Shape());
if (!BRep_Tool::Degenerated(aE)) {
continue;
}
//
nVD = aSI.SubShapes().First();
const TopoDS_Shape& aVD = myDS->Shape(nVD);
//
if (!aMVC.Contains(aVD)) {
continue;
}
//
if (myDS->IsNewShape(nVD)) {
continue;
}
//
if (myDS->HasInterf(nVD)) {
continue;
}
//
aBB.Add(aC, aE);
}
//
myRC=aC;
}
//=======================================================================
//function : BuildShape
//purpose :
//=======================================================================
void BOPAlgo_BOP::BuildShape()
{
BuildRC();
//
if ((myOperation == BOPAlgo_FUSE) && (myDims[0] == 3)) {
BuildSolid();
return;
}
//
Standard_Integer i;
TopAbs_ShapeEnum aType, aT1, aT2;
BOPCol_ListOfShape aLSC, aLCB;
BOPCol_ListIteratorOfListOfShape aItLS, aItLSIm, aItLCB;
TopoDS_Iterator aIt;
BRep_Builder aBB;
TopoDS_Shape aRC, aRCB;
//
BOPCol_MapOfShape aMSRC;
BOPTools::MapShapes(myRC, aMSRC);
//
// collect images of containers
for (i = 0; i < 2; ++i) {
const BOPCol_ListOfShape& aLS = !i ? myArguments : myTools;
//
aItLS.Initialize(aLS);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aS = aItLS.Value();
//
CollectContainers(aS, aLSC);
}
}
// make containers
BOPCol_ListOfShape aLCRes;
aItLS.Initialize(aLSC);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aSC = aItLS.Value();
//
BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC);
//
aIt.Initialize(aSC);
for (; aIt.More(); aIt.Next()) {
const TopoDS_Shape& aS = aIt.Value();
if (myImages.IsBound(aS)) {
const BOPCol_ListOfShape& aLSIm = myImages.Find(aS);
//
aItLSIm.Initialize(aLSIm);
for (; aItLSIm.More(); aItLSIm.Next()) {
const TopoDS_Shape& aSIm = aItLSIm.Value();
if (aMSRC.Contains(aSIm)) {
aBB.Add(aRC, aSIm);
}
}
}
else if (aMSRC.Contains(aS)) {
aBB.Add(aRC, aS);
}
}
//
aType = aSC.ShapeType();
switch (aType) {
case TopAbs_WIRE: {
aT1 = TopAbs_VERTEX;
aT2 = TopAbs_EDGE;
break;
}
case TopAbs_SHELL: {
aT1 = TopAbs_EDGE;
aT2 = TopAbs_FACE;
break;
}
default: {
aT1 = TopAbs_FACE;
aT2 = TopAbs_SOLID;
}
}
//
aLCB.Clear();
BOPTools_AlgoTools::MakeConnexityBlocks(aRC, aT1, aT2, aLCB);
if (aLCB.IsEmpty()) {
continue;
}
//
aItLCB.Initialize(aLCB);
for (; aItLCB.More(); aItLCB.Next()) {
BOPTools_AlgoTools::MakeContainer(aType, aRCB);
//
const TopoDS_Shape& aCB = aItLCB.Value();
aIt.Initialize(aCB);
for (; aIt.More(); aIt.Next()) {
const TopoDS_Shape& aCBS = aIt.Value();
aBB.Add(aRCB, aCBS);
}
//
if (aType == TopAbs_WIRE) {
// reorient wire
BOPTools_AlgoTools::OrientEdgesOnWire(aRCB);
}
else if (aType == TopAbs_SHELL) {
BOPTools_AlgoTools::OrientFacesOnShell(aRCB);
}
//
aRCB.Orientation(aSC.Orientation());
//
aLCRes.Append(aRCB);
}
}
//
RemoveDuplicates(aLCRes);
//
// add containers to result
TopoDS_Compound aResult;
aBB.MakeCompound(aResult);
//
aItLS.Initialize(aLCRes);
for (; aItLS.More(); aItLS.Next()) {
aBB.Add(aResult, aItLS.Value());
}
//
// add the rest of the shapes into result
BOPCol_MapOfShape aMSResult;
BOPTools::MapShapes(aResult, aMSResult);
//
aIt.Initialize(myRC);
for (; aIt.More(); aIt.Next()) {
const TopoDS_Shape& aS = aIt.Value();
if (aMSResult.Add(aS)) {
aBB.Add(aResult, aS);
}
}
//
myShape = aResult;
}
//=======================================================================
//function : BuildSolid
//purpose :
//=======================================================================
void BOPAlgo_BOP::BuildSolid()
{
Standard_Boolean bHasInterf, bHasSharedFaces;
Standard_Integer i, aNbF, aNbSx, iX, iErr, aNbZ;
TopAbs_Orientation aOr, aOr1;
TopoDS_Iterator aIt;
TopoDS_Shape aRC;
BRep_Builder aBB;
TopExp_Explorer aExp;
BOPCol_IndexedMapOfShape aMFI;
BOPCol_IndexedDataMapOfShapeListOfShape aMFS, aMEF;
BOPCol_ListIteratorOfListOfShape aItLS;
BOPCol_ListOfShape aSFS;
BOPAlgo_BuilderSolid aSB;
BOPCol_MapOfShape aMSA, aMZ;
BOPTools_IndexedDataMapOfSetShape aDMSTS;
BOPCol_ListOfShape aLSC;
//
myErrorStatus=0;
//
// Map of of Solids of Arguments
for (i=0; i<2; ++i) {
const BOPCol_ListOfShape& aLSA=(i) ? myArguments : myTools;
aItLS.Initialize(aLSA);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aSA=aItLS.Value();
//
CollectContainers(aSA, aLSC);
//
aExp.Init(aSA, TopAbs_SOLID);
for (; aExp.More(); aExp.Next()) {
const TopoDS_Shape& aZA=aExp.Current();
aMSA.Add(aZA);
//
BOPTools::MapShapesAndAncestors(aZA,
TopAbs_FACE,
TopAbs_SOLID,
aMFS);
}
}
}
//
aNbF=aMFS.Extent();
for (i=1; i<aNbF; ++i) {
//const TopoDS_Shape& aFA=aMFZA.FindKey(i);
const BOPCol_ListOfShape& aLZA=aMFS(i);
aNbZ=aLZA.Extent();
if (aNbZ > 1) {
aItLS.Initialize(aLZA);
for(; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aZA=aItLS.Value();
aMZ.Add(aZA);
}
}
}
//
aMFS.Clear();
//
aIt.Initialize(myRC);
for (; aIt.More(); aIt.Next()) {
const TopoDS_Shape& aSx=aIt.Value();
if (aMSA.Contains(aSx)) {
iX=myDS->Index(aSx);
bHasInterf=myDS->HasInterf(iX);
bHasSharedFaces=aMZ.Contains(aSx);
//
if (!bHasInterf && !bHasSharedFaces) {
// It means that the solid aSx will be added
// to the result as is.
// The solid aSx will not participate
// in creation of a new solid(s).
BOPTools_Set aST;
//
aST.Add(aSx, TopAbs_FACE);
//
if (!aDMSTS.Contains(aST)) {
aDMSTS.Add(aST, aSx);
}
continue;
}
}
//
aExp.Init(aSx, TopAbs_FACE);
for (; aExp.More(); aExp.Next()) {
const TopoDS_Shape& aFx=aExp.Current();
//
aOr=aFx.Orientation();
if (aOr==TopAbs_INTERNAL) {
aMFI.Add(aFx);
continue;
}
//
if (!aMFS.Contains(aFx)) {
BOPCol_ListOfShape aLSx;
//
aLSx.Append(aSx);
aMFS.Add(aFx, aLSx);
}
else {
iX=aMFS.FindIndex(aFx);
const TopoDS_Shape& aFx1=aMFS.FindKey(iX);
aOr1=aFx1.Orientation();
if (aOr1!=aOr) {
BOPCol_ListOfShape& aLSx=aMFS.ChangeFromKey(aFx);
aLSx.Append(aSx);
aMFS.Add(aFx, aLSx);
}
}
}
} // for (; aIt.More(); aIt.Next()) {
//faces that will be added in the end;
BOPCol_ListOfShape aLF, aLFx;
// SFS
aNbF=aMFS.Extent();
for (i=1; i<=aNbF; ++i) {
const TopoDS_Shape& aFx=aMFS.FindKey(i);
const BOPCol_ListOfShape& aLSx=aMFS(i);
aNbSx=aLSx.Extent();
if (aNbSx==1) {
BOPTools::MapShapesAndAncestors
(aFx,TopAbs_EDGE, TopAbs_FACE, aMEF);
if (IsBoundSplits(aFx, aMEF)){
aLFx.Append(aFx);
continue;
}
aLF.Append(aFx);
}
}
aItLS.Initialize(aLF);
for(; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aFx=aItLS.Value();
aSFS.Append(aFx);
}
// add faces from aLFx to aSFS;
aItLS.Initialize(aLFx);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aFx=aItLS.Value();
aSFS.Append(aFx);
}
//
aNbF=aMFI.Extent();
for (i=1; i<=aNbF; ++i) {
TopoDS_Shape aFx;
//
aFx=aMFI.FindKey(i);
aFx.Orientation(TopAbs_FORWARD);
aSFS.Append(aFx);
aFx.Orientation(TopAbs_REVERSED);
aSFS.Append(aFx);
}
//
// BuilderSolid
BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC);
//
aSB.SetContext(myContext);
aSB.SetShapes(aSFS);
aSB.Perform();
iErr=aSB.ErrorStatus();
if (iErr) {
myErrorStatus=30; // SolidBuilder failed
return;
}
//
const BOPCol_ListOfShape& aLSR=aSB.Areas();
//
aItLS.Initialize(aLSR);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aSR=aItLS.Value();
aBB.Add(aRC, aSR);
}
//
aNbSx = aDMSTS.Extent();
for (i = 1; i <= aNbSx; ++i) {
const TopoDS_Shape& aSx = aDMSTS(i);
aBB.Add(aRC, aSx);
}
//
if (aLSC.IsEmpty()) {
// no Compsolids in arguments
myShape=aRC;
return;
}
//
// build new Compsolids from new solids containing splits
// of faces from arguments of type Compsolid
//
TopoDS_Shape aResult;
BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aResult);
//
// optimization for one solid in the result
if (aLSR.Extent() == 1 && !aNbSx) {
TopoDS_Shape aCS;
BOPTools_AlgoTools::MakeContainer(TopAbs_COMPSOLID, aCS);
aBB.Add(aCS, aLSR.First());
//
aBB.Add(aResult, aCS);
myShape = aResult;
return;
}
//
// get splits of faces of the Compsolid arguments
BOPCol_MapOfShape aMFCs;
aItLS.Initialize(aLSC);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aCs = aItLS.Value();
aExp.Init(aCs, TopAbs_FACE);
for (; aExp.More(); aExp.Next()) {
const TopoDS_Shape& aF = aExp.Current();
const BOPCol_ListOfShape* pLFIm = myImages.Seek(aF);
if (!pLFIm) {
aMFCs.Add(aF);
}
else {
BOPCol_ListIteratorOfListOfShape aItLFIm(*pLFIm);
for (; aItLFIm.More(); aItLFIm.Next()) {
aMFCs.Add(aItLFIm.Value());
}
}
}
}
//
// build connexity blocks from new solids
BOPCol_ListOfShape aLCBS;
BOPTools_AlgoTools::MakeConnexityBlocks(aRC, TopAbs_FACE, TopAbs_SOLID, aLCBS);
//
aItLS.Initialize(aLCBS);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aCB = aItLS.Value();
//
// check if the Compsolid should be created
aExp.Init(aCB, TopAbs_FACE);
for (; aExp.More(); aExp.Next()) {
if (aMFCs.Contains(aExp.Current())) {
break;
}
}
//
if (!aExp.More()) {
// add solids directly into result as their origins are not Compsolids
for (aIt.Initialize(aCB); aIt.More(); aIt.Next()) {
aBB.Add(aResult, aIt.Value());
}
continue;
}
//
// make Compsolid
TopoDS_Shape aCS;
BOPTools_AlgoTools::MakeContainer(TopAbs_COMPSOLID, aCS);
//
aIt.Initialize(aCB);
for (; aIt.More(); aIt.Next()) {
aBB.Add(aCS, aIt.Value());
}
//
aBB.Add(aResult, aCS);
}
//
myShape = aResult;
}
//=======================================================================
//function : IsBoundSplits
//purpose :
//=======================================================================
Standard_Boolean BOPAlgo_BOP::IsBoundSplits
(const TopoDS_Shape& aS,
BOPCol_IndexedDataMapOfShapeListOfShape& aMEF)
{
Standard_Boolean bRet = Standard_False;
if (mySplits.IsBound(aS) || myOrigins.IsBound(aS)) {
return !bRet;
}
BOPCol_ListIteratorOfListOfShape aIt;
Standard_Integer aNbLS;
TopAbs_Orientation anOr;
//
//check face aF may be connected to face from mySplits
TopExp_Explorer aExp(aS, TopAbs_EDGE);
for (; aExp.More(); aExp.Next()) {
const TopoDS_Edge& aE = (*(TopoDS_Edge*)(&aExp.Current()));
//
anOr = aE.Orientation();
if (anOr==TopAbs_INTERNAL) {
continue;
}
//
if (BRep_Tool::Degenerated(aE)) {
continue;
}
//
const BOPCol_ListOfShape& aLS=aMEF.FindFromKey(aE);
aNbLS = aLS.Extent();
if (!aNbLS) {
continue;
}
//
aIt.Initialize(aLS);
for (; aIt.More(); aIt.Next()) {
const TopoDS_Shape& aSx = aIt.Value();
if (mySplits.IsBound(aSx) || myOrigins.IsBound(aS)) {
return !bRet;
}
}
}
//
return bRet;
}
//=======================================================================
//function : TypeToExplore
//purpose :
//=======================================================================
TopAbs_ShapeEnum TypeToExplore(const Standard_Integer theDim)
{
TopAbs_ShapeEnum aRet;
//
switch(theDim) {
case 0:
aRet=TopAbs_VERTEX;
break;
case 1:
aRet=TopAbs_EDGE;
break;
case 2:
aRet=TopAbs_FACE;
break;
case 3:
aRet=TopAbs_SOLID;
break;
default:
aRet=TopAbs_SHAPE;
break;
}
return aRet;
}
//=======================================================================
//function : CollectContainers
//purpose :
//=======================================================================
void CollectContainers(const TopoDS_Shape& theS,
BOPCol_ListOfShape& theLSC)
{
TopAbs_ShapeEnum aType = theS.ShapeType();
if (aType == TopAbs_WIRE ||
aType == TopAbs_SHELL ||
aType == TopAbs_COMPSOLID) {
theLSC.Append(theS);
return;
}
//
if (aType != TopAbs_COMPOUND) {
return;
}
//
TopoDS_Iterator aIt(theS);
for (; aIt.More(); aIt.Next()) {
const TopoDS_Shape& aS = aIt.Value();
CollectContainers(aS, theLSC);
}
}
//=======================================================================
//function : RemoveDuplicates
//purpose : Filters the containers with identical contents
//=======================================================================
void RemoveDuplicates(BOPCol_ListOfShape& theContainers)
{
RemoveDuplicates(theContainers, TopAbs_WIRE);
RemoveDuplicates(theContainers, TopAbs_SHELL);
RemoveDuplicates(theContainers, TopAbs_COMPSOLID);
}
//=======================================================================
//function : RemoveDuplicates
//purpose : Filters the containers of given type with identical contents
//=======================================================================
void RemoveDuplicates(BOPCol_ListOfShape& theContainers,
const TopAbs_ShapeEnum theType)
{
// get containers of given type
BOPCol_ListOfShape aLC;
BOPCol_ListIteratorOfListOfShape aItLC(theContainers);
for (; aItLC.More(); aItLC.Next()) {
const TopoDS_Shape& aC = aItLC.Value();
if (aC.ShapeType() == theType) {
aLC.Append(aC);
}
}
//
if (aLC.IsEmpty()) {
return;
}
//
// map containers to compare its contents
NCollection_IndexedDataMap<TopoDS_Shape, BOPCol_MapOfShape> aContents;
//
aItLC.Initialize(aLC);
for (; aItLC.More(); aItLC.Next()) {
const TopoDS_Shape& aC = aItLC.Value();
//
BOPCol_MapOfShape& aMC = aContents(aContents.Add(aC, BOPCol_MapOfShape()));
//
TopoDS_Iterator aIt(aC);
for (; aIt.More(); aIt.Next()) {
aMC.Add(aIt.Value());
}
}
//
// compare the contents of the containers and find duplicates
BOPCol_MapOfShape aDuplicates;
//
Standard_Integer i, j, aNb = aContents.Extent();
for (i = 1; i <= aNb; ++i) {
const TopoDS_Shape& aCi = aContents.FindKey(i);
if (aDuplicates.Contains(aCi)) {
continue;
}
const BOPCol_MapOfShape& aMi = aContents(i);
Standard_Integer aNbi = aMi.Extent();
//
for (j = i + 1; j <= aNb; ++j) {
const TopoDS_Shape& aCj = aContents.FindKey(j);
if (aDuplicates.Contains(aCj)) {
continue;
}
const BOPCol_MapOfShape& aMj = aContents(j);
Standard_Integer aNbj = aMj.Extent();
//
Standard_Integer aNbCommon = NbCommonItemsInMap(aMi, aMj);
//
if (aNbj == aNbCommon) {
aDuplicates.Add(aCj);
continue;
}
//
if (aNbi == aNbCommon) {
aDuplicates.Add(aCi);
break;
}
}
}
//
if (aDuplicates.IsEmpty()) {
return;
}
//
// remove duplicating containers
aItLC.Initialize(theContainers);
for (; aItLC.More(); ) {
const TopoDS_Shape& aC = aItLC.Value();
if (aDuplicates.Contains(aC)) {
theContainers.Remove(aItLC);
continue;
}
aItLC.Next();
}
}
//=======================================================================
//function : NbCommonItemsInMap
//purpose : Counts the items contained in both maps
//=======================================================================
Standard_Integer NbCommonItemsInMap(const BOPCol_MapOfShape& theM1,
const BOPCol_MapOfShape& theM2)
{
const BOPCol_MapOfShape* aMap1 = &theM1;
const BOPCol_MapOfShape* aMap2 = &theM2;
//
if (theM2.Extent() < theM1.Extent()) {
aMap1 = &theM2;
aMap2 = &theM1;
}
//
Standard_Integer iCommon = 0;
for (BOPCol_MapIteratorOfMapOfShape aIt(*aMap1); aIt.More(); aIt.Next()) {
if (aMap2->Contains(aIt.Value())) {
++iCommon;
}
}
return iCommon;
}