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_Tools.cxx
kgv d6e050ac44 0032008: Modeling Algorithms - disallow implicit copy of Extrema algorithms
Extrema_GenExtPS now prefers resizing of Array2 tables instead of managing tables by extra handles.
Removed unsafe casts to Adaptor3d_SurfacePtr/Adaptor3d_CurvePtr in Extrema classes.
Removed unsafe casts to curve adaptors in Extrema_ExtCC, Extrema_ExtCC2d classes.

Extrema_GenExtPS, Extrema_GenExtSS, Extrema_ExtCS -
copies by value are now disallowed;
several unexpected places copying the object have been fixed.

IntTools_Context - maps of void* have been replaced by typed maps.
2021-03-05 17:31:07 +03:00

1759 lines
55 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_Tools.hxx>
#include <BOPAlgo_Builder.hxx>
#include <BOPAlgo_BuilderFace.hxx>
#include <BOPDS_CommonBlock.hxx>
#include <BOPDS_DataMapOfPaveBlockListOfPaveBlock.hxx>
#include <BOPDS_DS.hxx>
#include <BOPDS_IndexedMapOfPaveBlock.hxx>
#include <BOPDS_MapOfPaveBlock.hxx>
#include <BOPDS_PaveBlock.hxx>
#include <BOPTools_AlgoTools.hxx>
#include <BOPTools_AlgoTools2D.hxx>
#include <BOPTools_BoxTree.hxx>
#include <BOPTools_Parallel.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepBndLib.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepLib.hxx>
#include <Bnd_Tools.hxx>
#include <GeomAPI_ProjectPointOnCurve.hxx>
#include <GeomAPI_ProjectPointOnSurf.hxx>
#include <gp_Circ.hxx>
#include <gp_Dir.hxx>
#include <gp_Elips.hxx>
#include <gp_Hypr.hxx>
#include <gp_Parab.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <IntTools_Context.hxx>
#include <NCollection_IncAllocator.hxx>
#include <NCollection_Vector.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <TColStd_IndexedMapOfInteger.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopTools_MapOfShape.hxx>
#include <algorithm>
typedef NCollection_IndexedDataMap
<TopoDS_Shape, gp_Dir, TopTools_ShapeMapHasher> BOPAlgo_IndexedDataMapOfShapeDir;
typedef NCollection_IndexedDataMap
<TopoDS_Shape, gp_Pln, TopTools_ShapeMapHasher> BOPAlgo_IndexedDataMapOfShapePln;
static
void MakeWires(const TopTools_IndexedMapOfShape& theEdges,
TopoDS_Compound& theWires,
const Standard_Boolean theCheckUniquePlane,
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
TopTools_MapOfShape& theMEdgesNoUniquePlane);
static
Standard_Boolean FindPlane(const BRepAdaptor_Curve& theCurve,
gp_Pln& thePlane);
static
Standard_Boolean FindPlane(const TopoDS_Shape& theWire,
gp_Pln& thePlane,
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
TopTools_MapOfShape& theMEdgesNoUniquePlane);
static
Standard_Boolean FindEdgeTangent(const TopoDS_Edge& theEdge,
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
gp_Dir& theTgt);
static
Standard_Boolean FindEdgeTangent(const BRepAdaptor_Curve& theCurve,
gp_Vec& theTangent);
//=======================================================================
//function : FillMap
//purpose :
//=======================================================================
void BOPAlgo_Tools::FillMap(const Handle(BOPDS_PaveBlock)& aPB,
const Standard_Integer nF,
BOPDS_IndexedDataMapOfPaveBlockListOfInteger& aMPBLI,
const Handle(NCollection_BaseAllocator)& aAllocator)
{
TColStd_ListOfInteger *pLI = aMPBLI.ChangeSeek(aPB);
if (!pLI) {
pLI = &aMPBLI(aMPBLI.Add(aPB, TColStd_ListOfInteger(aAllocator)));
}
pLI->Append(nF);
}
//=======================================================================
//function : PerformCommonBlocks
//purpose :
//=======================================================================
void BOPAlgo_Tools::PerformCommonBlocks(BOPDS_IndexedDataMapOfPaveBlockListOfPaveBlock& aMPBLPB,
const Handle(NCollection_BaseAllocator)& aAllocator,
BOPDS_PDS& pDS,
const Handle(IntTools_Context)& theContext)
{
Standard_Integer aNbCB;
//
aNbCB=aMPBLPB.Extent();
if (!aNbCB) {
return;
}
// Make Blocks of the pave blocks
NCollection_List<BOPDS_ListOfPaveBlock> aMBlocks(aAllocator);
BOPAlgo_Tools::MakeBlocks<Handle(BOPDS_PaveBlock), TColStd_MapTransientHasher>(aMPBLPB, aMBlocks, aAllocator);
// Use temporary allocator for the local fence map
Handle(NCollection_IncAllocator) anAllocTmp = new NCollection_IncAllocator;
NCollection_List<BOPDS_ListOfPaveBlock>::Iterator aItB(aMBlocks);
for (; aItB.More(); aItB.Next()) {
const BOPDS_ListOfPaveBlock& aLPB = aItB.Value();
Standard_Integer aNbPB = aLPB.Extent();
if (aNbPB < 2)
continue;
// Reset the allocator
anAllocTmp->Reset();
// New common block
Handle(BOPDS_CommonBlock) aCB;
// Faces of the common block
TColStd_ListOfInteger aLFaces;
// Fence map to avoid duplicates in the list of faces of the common block
TColStd_MapOfInteger aMFaces(1, anAllocTmp);
BOPDS_ListIteratorOfListOfPaveBlock aItLPB(aLPB);
for (; aItLPB.More(); aItLPB.Next())
{
const Handle(BOPDS_PaveBlock)& aPB = aItLPB.Value();
if (pDS->IsCommonBlock(aPB))
{
const Handle(BOPDS_CommonBlock)& aCBx = pDS->CommonBlock(aPB);
// Move all faces to the new common block
TColStd_ListIteratorOfListOfInteger aItLF(aCBx->Faces());
for (; aItLF.More(); aItLF.Next())
{
const Standard_Integer nF = aItLF.Value();
// Append to common list avoiding duplicates
if (aMFaces.Add(nF))
aLFaces.Append(nF);
}
if (aCB.IsNull())
aCB = aCBx;
}
}
if (aCB.IsNull())
aCB = new BOPDS_CommonBlock;
aCB->SetPaveBlocks(aLPB);
aCB->SetFaces(aLFaces);
for (aItLPB.Initialize(aLPB); aItLPB.More(); aItLPB.Next())
pDS->SetCommonBlock(aItLPB.Value(), aCB);
// Compute tolerance for Common Block
Standard_Real aTolCB = BOPAlgo_Tools::ComputeToleranceOfCB(aCB, pDS, theContext);
aCB->SetTolerance(aTolCB);
}
}
//=======================================================================
//function : PerformCommonBlocks
//purpose :
//=======================================================================
void BOPAlgo_Tools::PerformCommonBlocks(const BOPDS_IndexedDataMapOfPaveBlockListOfInteger& aMPBLI,
const Handle(NCollection_BaseAllocator)& ,//aAllocator
BOPDS_PDS& pDS,
const Handle(IntTools_Context)& theContext)
{
Standard_Integer nF, i, aNb;
TColStd_ListIteratorOfListOfInteger aItLI;
Handle(BOPDS_PaveBlock) aPB;
Handle(BOPDS_CommonBlock) aCB;
//
aNb=aMPBLI.Extent();
for (i=1; i<=aNb; ++i) {
aPB=aMPBLI.FindKey(i);
if (pDS->IsCommonBlock(aPB)) {
aCB=pDS->CommonBlock(aPB);
}
else {
aCB=new BOPDS_CommonBlock;
aCB->AddPaveBlock(aPB);
}
//
const TColStd_ListOfInteger& aLI=aMPBLI.FindFromKey(aPB);
TColStd_ListOfInteger aNewFaces;
const TColStd_ListOfInteger& anOldFaces = aCB->Faces();
aItLI.Initialize(aLI);
for (; aItLI.More(); aItLI.Next()) {
nF=aItLI.Value();
// the both lists aLI and anOldFaces are expected to be short,
// so we can allow to run nested loop here
TColStd_ListIteratorOfListOfInteger it(anOldFaces);
for (; it.More(); it.Next()) {
if (it.Value() == nF)
break;
}
if (!it.More()) {
aNewFaces.Append(nF);
}
}
aCB->AppendFaces(aNewFaces);
pDS->SetCommonBlock(aPB, aCB);
// Compute tolerance for Common Block
Standard_Real aTolCB = BOPAlgo_Tools::ComputeToleranceOfCB(aCB, pDS, theContext);
aCB->SetTolerance(aTolCB);
}
}
//=======================================================================
//function : ComputeToleranceOfCB
//purpose :
//=======================================================================
Standard_Real BOPAlgo_Tools::ComputeToleranceOfCB
(const Handle(BOPDS_CommonBlock)& theCB,
const BOPDS_PDS theDS,
const Handle(IntTools_Context)& theContext)
{
Standard_Real aTolMax = 0.;
if (theCB.IsNull()) {
return aTolMax;
}
//
const Handle(BOPDS_PaveBlock)& aPBR = theCB->PaveBlock1();
Standard_Integer nE = aPBR->OriginalEdge();
const TopoDS_Edge& aEOr = *(TopoDS_Edge*)&theDS->Shape(nE);
aTolMax = BRep_Tool::Tolerance(aEOr);
//
const BOPDS_ListOfPaveBlock& aLPB = theCB->PaveBlocks();
const TColStd_ListOfInteger& aLFI = theCB->Faces();
//
if ((aLPB.Extent() < 2) && aLFI.IsEmpty()) {
return aTolMax;
}
//
const Standard_Integer aNbPnt = 11;
Standard_Real aTol, aT, aT1, aT2, aDt;
gp_Pnt aP;
//
const Handle(Geom_Curve)& aC3D = BRep_Tool::Curve(aEOr, aT1, aT2);
//
aPBR->Range(aT1, aT2);
aDt = (aT2 - aT1) / (aNbPnt + 1);
//
Handle(IntTools_Context) aCtx = theContext;
if (aCtx.IsNull())
aCtx = new IntTools_Context();
// compute max tolerance for common blocks on edges
if (aLPB.Extent() > 1) {
// compute max distance between edges
BOPDS_ListIteratorOfListOfPaveBlock aItPB;
GeomAPI_ProjectPointOnCurve aProjPC;
//
aItPB.Initialize(aLPB);
for (; aItPB.More(); aItPB.Next()) {
const Handle(BOPDS_PaveBlock)& aPB = aItPB.Value();
if (aPB == aPBR) {
continue;
}
//
nE = aPB->OriginalEdge();
const TopoDS_Edge& aE = *(TopoDS_Edge*)&theDS->Shape(nE);
aTol = BRep_Tool::Tolerance(aE);
//
aProjPC = aCtx->ProjPC(aE);
//
aT = aT1;
for (Standard_Integer i=1; i <= aNbPnt; i++) {
aT += aDt;
aC3D->D0(aT, aP);
aProjPC.Perform(aP);
if (aProjPC.NbPoints()) {
Standard_Real aTolNew = aTol + aProjPC.LowerDistance();
if (aTolNew > aTolMax) {
aTolMax = aTolNew;
}
}
}
}
}
//
// compute max tolerance for common blocks on faces
if (aLFI.Extent()) {
for (TColStd_ListIteratorOfListOfInteger aItLI (aLFI); aItLI.More(); aItLI.Next())
{
const Standard_Integer nF = aItLI.Value();
const TopoDS_Face& aF = *(TopoDS_Face*)&theDS->Shape(nF);
aTol = BRep_Tool::Tolerance(aF);
//
GeomAPI_ProjectPointOnSurf& aProjPS = aCtx->ProjPS(aF);
//
aT = aT1;
for (Standard_Integer i=1; i <= aNbPnt; i++) {
aT += aDt;
aC3D->D0(aT, aP);
aProjPS.Perform(aP);
if (aProjPS.NbPoints()) {
Standard_Real aTolNew = aTol + aProjPS.LowerDistance();
if (aTolNew > aTolMax) {
aTolMax = aTolNew;
}
}
}
}
}
//
return aTolMax;
}
//=======================================================================
//function : EdgesToWires
//purpose :
//=======================================================================
Standard_Integer BOPAlgo_Tools::EdgesToWires(const TopoDS_Shape& theEdges,
TopoDS_Shape& theWires,
const Standard_Boolean theShared,
const Standard_Real theAngTol)
{
Standard_Integer iErr = 0;
//
// 1. Check the input edges
//
// List of edges to process
TopTools_ListOfShape aLE;
//
TopExp_Explorer aExp(theEdges, TopAbs_EDGE);
for (; aExp.More(); aExp.Next()) {
const TopoDS_Edge& aE = TopoDS::Edge(aExp.Current());
if (!BRep_Tool::Degenerated(aE) && BRep_Tool::IsGeometric(aE)) {
aLE.Append(aExp.Current());
}
}
//
if (aLE.IsEmpty()) {
// no edges to process
iErr = 1;
return iErr;
}
//
BRep_Builder aBB;
TopoDS_Compound aRWires;
aBB.MakeCompound(aRWires);
//
if (aLE.Extent() == 1) {
TopoDS_Wire aWire;
aBB.MakeWire(aWire);
aBB.Add(aWire, aLE.First());
aBB.Add(aRWires, aWire);
theWires = aRWires;
return iErr;
}
//
// 2. Make compound of shared edges
TopoDS_Shape aSEdges;
//
if (!theShared) {
// intersect the edges if necessary
BOPAlgo_Builder aGF;
aGF.SetArguments(aLE);
aGF.Perform();
if (aGF.HasErrors()) {
// unable to share the edges
iErr = 2;
return iErr;
}
//
aSEdges = aGF.Shape();
}
else {
aBB.MakeCompound(TopoDS::Compound(aSEdges));
TopTools_ListIteratorOfListOfShape aItLE(aLE);
for (; aItLE.More(); aItLE.Next()) {
aBB.Add(aSEdges, aItLE.Value());
}
}
//
// 3. Find edges located in the same planes and make wires from them.
// If the plane cannot be found for a single edge, then it is necessary
// to find all pairs of connected edges with the same cross product.
// Try to compute the plane in which the edge is located
BOPAlgo_IndexedDataMapOfShapePln aDMEdgePln;
// Compute the tangent direction for the edges for which the plane is not defined
BOPAlgo_IndexedDataMapOfShapeDir aDMEdgeTgt;
//
// edges for which the plane is not found
TopTools_MapOfShape aMEdgesNoUniquePlane;
//
// edges for which the plane cannot be found on a single edge
TopoDS_Compound aLEdges;
aBB.MakeCompound(aLEdges);
//
aExp.Init(aSEdges, TopAbs_EDGE);
for (; aExp.More(); aExp.Next()) {
const TopoDS_Edge& aE = TopoDS::Edge(aExp.Current());
BRepAdaptor_Curve aBAC(aE);
//
gp_Pln aPln;
if (FindPlane(aBAC, aPln)) {
aDMEdgePln.Add(aE, aPln);
}
else {
gp_Vec aVT;
if (FindEdgeTangent(aBAC, aVT)) {
aDMEdgeTgt.Add(aE, gp_Dir(aVT));
aBB.Add(aLEdges, aE);
aMEdgesNoUniquePlane.Add(aE);
}
}
}
//
typedef NCollection_List<gp_Dir> BOPAlgo_ListOfDir;
//
// to avoid processing of the same edges in the same plane store
// the processed planes into a list and use it as a fence map
BOPAlgo_ListOfDir aLPFence;
//
// used edges
TopTools_MapOfShape aMEFence;
//
// look for a planes on the single edges
Standard_Integer i, j, aNbPlanes = aDMEdgePln.Extent(), aNbEdges = aDMEdgeTgt.Extent();
for (i = 1; i <= aNbPlanes; ++i) {
const TopoDS_Shape& aEI = aDMEdgePln.FindKey(i);
if (!aMEFence.Add(aEI)) {
continue;
}
//
const gp_Pln& aPlnI = aDMEdgePln(i);
const gp_Dir& aDI = aPlnI.Position().Direction();
//
aLPFence.Append(aDI);
//
TopTools_IndexedMapOfShape aMEPln;
aMEPln.Add(aEI);
//
TopTools_IndexedMapOfShape aMV;
TopExp::MapShapes(aEI, TopAbs_VERTEX, aMV);
//
// look for other edges with the plane parallel to current one
for (j = i + 1; j <= aNbPlanes; ++j) {
const gp_Dir& aDJ = aDMEdgePln(j).Position().Direction();
if (aDI.IsParallel(aDJ, theAngTol)) {
const TopoDS_Shape& aEJ = aDMEdgePln.FindKey(j);
aMEPln.Add(aEJ);
aMEFence.Add(aEJ);
TopExp::MapShapes(aEJ, TopAbs_VERTEX, aMV);
}
}
//
// look for all other edges located in the plane parallel to current one
TopoDS_Compound aCEPln;
aBB.MakeCompound(aCEPln);
//
for (j = 1; j <= aNbEdges; ++j) {
const gp_Dir& aDJ = aDMEdgeTgt(j);
if (aDI.IsNormal(aDJ, theAngTol)) {
aBB.Add(aCEPln, aDMEdgeTgt.FindKey(j));
}
}
//
// make blocks of these edges and check blocks to be connected
// to any of the already added edges or forming a wire themselves
TopTools_ListOfShape aLCBE;
BOPTools_AlgoTools::MakeConnexityBlocks(aCEPln, TopAbs_VERTEX, TopAbs_EDGE, aLCBE);
//
// make wire from each block
TopTools_ListIteratorOfListOfShape aItLCB(aLCBE);
for (; aItLCB.More(); aItLCB.Next()) {
const TopoDS_Shape& aCBE = aItLCB.Value();
//
// check connectivity
TopExp_Explorer aExpV(aCBE, TopAbs_VERTEX);
for (; aExpV.More(); aExpV.Next()) {
if (aMV.Contains(aExpV.Current())) {
break;
}
}
//
Standard_Boolean bAddBlock = aExpV.More();
if (!bAddBlock) {
// check if the edges are forming a wire
gp_Pln aPln;
bAddBlock = FindPlane(aCBE, aPln, aDMEdgeTgt, aMEdgesNoUniquePlane);
}
//
if (bAddBlock) {
// add edges
for (TopoDS_Iterator aItE(aCBE); aItE.More(); aItE.Next()) {
aMEPln.Add(aItE.Value());
}
}
}
//
MakeWires(aMEPln, aRWires, Standard_False, aDMEdgeTgt, aMEdgesNoUniquePlane);
}
//
// make connection map from vertices to edges to find the connected pairs
TopTools_IndexedDataMapOfShapeListOfShape aDMVE;
TopExp::MapShapesAndAncestors(aLEdges, TopAbs_VERTEX, TopAbs_EDGE, aDMVE);
//
// find planes for connected edges
Standard_Integer aNbV = aDMVE.Extent();
for (i = 1; i <= aNbV; ++i) {
const TopTools_ListOfShape& aLEI = aDMVE(i);
if (aLEI.Extent() < 2) {
continue;
}
//
TopTools_ListIteratorOfListOfShape aItLEI1(aLEI);
for (; aItLEI1.More(); aItLEI1.Next()) {
const TopoDS_Shape& aEI1 = aItLEI1.Value();
const gp_Dir& aDI1 = aDMEdgeTgt.FindFromKey(aEI1);
//
TopTools_ListIteratorOfListOfShape aItLEI2(aLEI);
for (; aItLEI2.More(); aItLEI2.Next()) {
const TopoDS_Shape& aEI2 = aItLEI2.Value();
if (aEI2.IsSame(aEI1)) {
continue;
}
//
const gp_Dir& aDI2 = aDMEdgeTgt.FindFromKey(aEI2);
//
if (aDI1.IsParallel(aDI2, theAngTol)) {
continue;
}
//
gp_Dir aDNI = aDI1^aDI2;
//
// check if this normal direction has not been checked yet
BOPAlgo_ListOfDir::Iterator aItLPln(aLPFence);
for (; aItLPln.More(); aItLPln.Next()) {
if (aDNI.IsParallel(aItLPln.Value(), theAngTol)) {
break;
}
}
if (aItLPln.More()) {
continue;
}
//
aLPFence.Append(aDNI);
//
// find all other edges in the plane parallel to current one
TopTools_IndexedMapOfShape aMEPln;
aMEPln.Add(aEI1);
aMEPln.Add(aEI2);
//
// iterate on all other edges to find all edges lying in the plane parallel to current one
for (j = 1; j <= aNbEdges; ++j) {
const gp_Dir& aDJ = aDMEdgeTgt(j);
if (aDNI.IsNormal(aDJ, theAngTol)) {
aMEPln.Add(aDMEdgeTgt.FindKey(j));
}
}
//
MakeWires(aMEPln, aRWires, Standard_True, aDMEdgeTgt, aMEdgesNoUniquePlane);
} // for (; aItLEI2.More(); aItLEI2.Next()) {
} // for (; aItLEI1.More(); aItLEI1.Next()) {
} // for (i = 1; i < aNb; ++i) {
//
// 4. Find unused edges and make wires from them
TopTools_IndexedMapOfShape aMEAlone, aMEUsed;
TopExp::MapShapes(aRWires, TopAbs_EDGE, aMEUsed);
//
for (i = 1; i <= aNbEdges; ++i) {
const TopoDS_Shape& aE = aDMEdgeTgt.FindKey(i);
if (!aMEUsed.Contains(aE)) {
aMEAlone.Add(aE);
}
}
//
MakeWires(aMEAlone, aRWires, Standard_False, aDMEdgeTgt, aMEdgesNoUniquePlane);
//
theWires = aRWires;
//
return iErr;
}
//=======================================================================
//function : WiresToFaces
//purpose :
//=======================================================================
Standard_Boolean BOPAlgo_Tools::WiresToFaces(const TopoDS_Shape& theWires,
TopoDS_Shape& theFaces,
const Standard_Real theAngTol)
{
BRep_Builder aBB;
TopTools_MapOfShape aMFence;
TopoDS_Compound aRFaces;
aBB.MakeCompound(aRFaces);
//
const Standard_Real aMax = 1.e+8;
//
// map to store the tangent vectors for the edges
BOPAlgo_IndexedDataMapOfShapeDir aDMEdgeTgt;
// maps to store the planes found for the wires
BOPAlgo_IndexedDataMapOfShapePln aDMWirePln;
// map to store the tolerance for the wire
NCollection_DataMap<TopoDS_Shape, Standard_Real, TopTools_ShapeMapHasher> aDMWireTol;
// edges for which the plane is not found
TopTools_MapOfShape aMEdgesNoUniquePlane;
//
// Find planes for the wires
TopExp_Explorer aExpW(theWires, TopAbs_WIRE);
for (; aExpW.More(); aExpW.Next()) {
const TopoDS_Wire& aWire = TopoDS::Wire(aExpW.Current());
gp_Pln aPlane;
if (FindPlane(aWire, aPlane, aDMEdgeTgt, aMEdgesNoUniquePlane)) {
aDMWirePln.Add(aWire, aPlane);
// find tolerance for the wire - max tolerance of its edges
aDMWireTol.Bind(aWire, BRep_Tool::MaxTolerance(aWire, TopAbs_EDGE));
}
}
//
Standard_Integer i, j, aNb = aDMWirePln.Extent();
for (i = 1; i <= aNb; ++i) {
const TopoDS_Shape& aWireI = aDMWirePln.FindKey(i);
if (aMFence.Contains(aWireI)) {
continue;
}
//
const gp_Pln& aPlnI = aDMWirePln(i);
//
TopTools_ListOfShape aLW;
aLW.Append(aWireI);
aMFence.Add(aWireI);
//
Standard_Real aTolI = aDMWireTol.Find(aWireI);
//
// Find other wires in the same plane
for (j = i + 1; j <= aNb; ++j) {
const TopoDS_Shape& aWireJ = aDMWirePln.FindKey(j);
if (aMFence.Contains(aWireJ)) {
continue;
}
//
// check if the planes are the same
const gp_Pln& aPlnJ = aDMWirePln(j);
// check direction of the planes
if (!aPlnI.Position().Direction().IsParallel(aPlnJ.Position().Direction(), theAngTol)) {
continue;
}
// check distance between the planes
Standard_Real aDist = aPlnI.Distance(aPlnJ.Location());
Standard_Real aTolJ = aDMWireTol.Find(aWireJ);
if (aDist > (aTolI + aTolJ)) {
continue;
}
//
aLW.Append(aWireJ);
aMFence.Add(aWireJ);
}
//
// Take the edges to build the face
TopTools_ListOfShape aLE;
TopTools_ListIteratorOfListOfShape aItLW(aLW);
for (; aItLW.More(); aItLW.Next()) {
TopoDS_Iterator aItE(aItLW.Value());
for (; aItE.More(); aItE.Next()) {
aLE.Append(aItE.Value().Oriented(TopAbs_FORWARD));
aLE.Append(aItE.Value().Oriented(TopAbs_REVERSED));
}
}
//
// build planar face
TopoDS_Face aFF = BRepBuilderAPI_MakeFace
(aPlnI, -aMax, aMax, -aMax, aMax).Face();
aFF.Orientation(TopAbs_FORWARD);
//
try {
OCC_CATCH_SIGNALS
//
// build pcurves for edges on this face
BRepLib::BuildPCurveForEdgesOnPlane(aLE, aFF);
//
// split the face with the edges
BOPAlgo_BuilderFace aBF;
aBF.SetShapes(aLE);
aBF.SetFace(aFF);
aBF.Perform();
if (aBF.HasErrors()) {
continue;
}
//
const TopTools_ListOfShape& aLFSp = aBF.Areas();
TopTools_ListIteratorOfListOfShape aItLF(aLFSp);
for (; aItLF.More(); aItLF.Next()) {
const TopoDS_Shape& aFSp = aItLF.ChangeValue();
aBB.Add(aRFaces, aFSp);
}
}
catch (Standard_Failure const&) {
continue;
}
}
//
// fix tolerances of the resulting faces
TopTools_IndexedMapOfShape aMEmpty;
BOPTools_AlgoTools::CorrectTolerances(aRFaces, aMEmpty, 0.05, Standard_False);
BOPTools_AlgoTools::CorrectShapeTolerances(aRFaces, aMEmpty, Standard_False);
//
theFaces = aRFaces;
return theFaces.NbChildren() > 0;
}
//=======================================================================
//function : MakeWires
//purpose : Makes wires from the separate blocks of the given edges
//=======================================================================
void MakeWires(const TopTools_IndexedMapOfShape& theEdges,
TopoDS_Compound& theWires,
const Standard_Boolean theCheckUniquePlane,
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
TopTools_MapOfShape& theMEdgesNoUniquePlane)
{
TopoDS_Compound aCE;
BRep_Builder().MakeCompound(aCE);
Standard_Integer i, aNbE = theEdges.Extent();
for (i = 1; i <= aNbE; ++i) {
BRep_Builder().Add(aCE, theEdges(i));
}
//
TopTools_ListOfShape aLCBE;
BOPTools_AlgoTools::MakeConnexityBlocks(aCE, TopAbs_VERTEX, TopAbs_EDGE, aLCBE);
//
// make wire from each block
TopTools_ListIteratorOfListOfShape aItLCB(aLCBE);
for (; aItLCB.More(); aItLCB.Next()) {
const TopoDS_Shape& aCBE = aItLCB.Value();
//
if (theCheckUniquePlane) {
gp_Pln aPln;
if (!FindPlane(aCBE, aPln, theDMEdgeTgt, theMEdgesNoUniquePlane)) {
continue;
}
}
//
TopoDS_Wire aWire;
BRep_Builder().MakeWire(aWire);
for (TopoDS_Iterator aItE(aCBE); aItE.More(); aItE.Next()) {
BRep_Builder().Add(aWire, aItE.Value());
}
//
BRep_Builder().Add(theWires, aWire);
}
}
//=======================================================================
//function : FindEdgeTangent
//purpose : Finds the tangent for the edge using the map
//=======================================================================
Standard_Boolean FindEdgeTangent(const TopoDS_Edge& theEdge,
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
gp_Dir& theTgt)
{
gp_Dir *pDTE = theDMEdgeTgt.ChangeSeek(theEdge);
if (!pDTE) {
gp_Vec aVTE;
BRepAdaptor_Curve aBAC(theEdge);
if (!FindEdgeTangent(aBAC, aVTE)) {
return Standard_False;
}
pDTE = &theDMEdgeTgt(theDMEdgeTgt.Add(theEdge, gp_Dir(aVTE)));
}
theTgt = *pDTE;
return Standard_True;
}
//=======================================================================
//function : FindEdgeTangent
//purpose : Finds the tangent for the edge
//=======================================================================
Standard_Boolean FindEdgeTangent(const BRepAdaptor_Curve& theCurve,
gp_Vec& theTangent)
{
if (!theCurve.Is3DCurve()) {
return Standard_False;
}
// for the line the tangent is defined by the direction
if (theCurve.GetType() == GeomAbs_Line) {
theTangent = theCurve.Line().Position().Direction();
return Standard_True;
}
//
// for other curves take D1 and check for its length
Standard_Real aT, aT1(theCurve.FirstParameter()), aT2(theCurve.LastParameter());
const Standard_Integer aNbP = 11;
const Standard_Real aDt = (aT2 - aT1) / aNbP;
//
for (aT = aT1 + aDt; aT <= aT2; aT += aDt) {
gp_Pnt aP;
theCurve.D1(aT, aP, theTangent);
if (theTangent.Magnitude() > Precision::Confusion()) {
return Standard_True;
}
}
//
return Standard_False;
}
//=======================================================================
//function : FindPlane
//purpose : Finds the plane in which the edge is located
//=======================================================================
Standard_Boolean FindPlane(const BRepAdaptor_Curve& theCurve,
gp_Pln& thePlane)
{
if (!theCurve.Is3DCurve()) {
return Standard_False;
}
//
Standard_Boolean bFound = Standard_True;
gp_Vec aVN;
switch (theCurve.GetType()) {
case GeomAbs_Line:
return Standard_False;
case GeomAbs_Circle:
aVN = theCurve.Circle().Position().Direction();
break;
case GeomAbs_Ellipse:
aVN = theCurve.Ellipse().Position().Direction();
break;
case GeomAbs_Hyperbola:
aVN = theCurve.Hyperbola().Position().Direction();
break;
case GeomAbs_Parabola:
aVN = theCurve.Parabola().Position().Direction();
break;
default: {
// for all other types of curve compute two tangent vectors
// on the curve and cross them
bFound = Standard_False;
Standard_Real aT, aT1(theCurve.FirstParameter()), aT2(theCurve.LastParameter());
const Standard_Integer aNbP = 11;
const Standard_Real aDt = (aT2 - aT1) / aNbP;
//
aT = aT1;
gp_Pnt aP1;
gp_Vec aV1;
theCurve.D1(aT, aP1, aV1);
//
for (aT = aT1 + aDt; aT <= aT2; aT += aDt) {
gp_Pnt aP2;
gp_Vec aV2;
theCurve.D1(aT, aP2, aV2);
//
aVN = aV1^aV2;
if (aVN.Magnitude() > Precision::Confusion()) {
bFound = Standard_True;
break;
}
}
break;
}
}
//
if (bFound) {
thePlane = gp_Pln(theCurve.Value(theCurve.FirstParameter()), gp_Dir(aVN));
}
return bFound;
}
//=======================================================================
//function : FindPlane
//purpose : Finds the plane in which the wire is located
//=======================================================================
Standard_Boolean FindPlane(const TopoDS_Shape& theWire,
gp_Pln& thePlane,
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
TopTools_MapOfShape& theMEdgesNoUniquePlane)
{
TopExp_Explorer aExpE1(theWire, TopAbs_EDGE);
if (!aExpE1.More()) {
return Standard_False;
}
//
// try to find two not parallel edges in wire to get normal of the plane
for (; aExpE1.More(); aExpE1.Next()) {
// get the first edge in the wire
const TopoDS_Edge& aE1 = TopoDS::Edge(aExpE1.Current());
//
// find tangent for the first edge
gp_Dir aDTE1;
if (!FindEdgeTangent(aE1, theDMEdgeTgt, aDTE1)) {
continue;
}
//
// find the other edge not parallel to the first one
TopExp_Explorer aExpE2(theWire, TopAbs_EDGE);
for (; aExpE2.More(); aExpE2.Next()) {
const TopoDS_Edge& aE2 = TopoDS::Edge(aExpE2.Current());
if (aE1.IsSame(aE2)) {
continue;
}
//
// find tangent for the second edge
gp_Dir aDTE2;
if (!FindEdgeTangent(aE2, theDMEdgeTgt, aDTE2)) {
continue;
}
//
if (aDTE1.IsParallel(aDTE2, Precision::Angular())) {
continue;
}
//
gp_Dir aDN = aDTE1^aDTE2;
//
TopoDS_Iterator aItV(aE1);
thePlane = gp_Pln(BRep_Tool::Pnt(TopoDS::Vertex(aItV.Value())), aDN);
return Standard_True;
}
}
//
// try to compute normal on the single edge
aExpE1.Init(theWire, TopAbs_EDGE);
for (; aExpE1.More(); aExpE1.Next()) {
const TopoDS_Edge& aE = TopoDS::Edge(aExpE1.Current());
if (theMEdgesNoUniquePlane.Contains(aE)) {
continue;
}
BRepAdaptor_Curve aBAC(aE);
if (FindPlane(aBAC, thePlane)) {
return Standard_True;
}
theMEdgesNoUniquePlane.Add(aE);
}
return Standard_False;
}
/////////////////////////////////////////////////////////////////////////
//=======================================================================
//class : BOPAlgo_PairVerticesSelector
//purpose :
//=======================================================================
class BOPAlgo_PairVerticesSelector : public BOPTools_BoxPairSelector
{
public:
BOPAlgo_PairVerticesSelector()
: myVertices(NULL),
myFuzzyValue(Precision::Confusion())
{}
//! Sets the map of vertices with tolerances
void SetMapOfVerticesTolerances (const TopTools_IndexedDataMapOfShapeReal& theVertices)
{
myVertices = &theVertices;
}
//! Sets the fuzzy value
void SetFuzzyValue (const Standard_Real theFuzzyValue)
{
myFuzzyValue = theFuzzyValue;
}
//! Checks and accepts the pair of elements.
virtual Standard_Boolean Accept (const Standard_Integer theID1,
const Standard_Integer theID2) Standard_OVERRIDE
{
if (!RejectElement (theID1, theID2))
{
const Standard_Integer anID1 = this->myBVHSet1->Element (theID1);
const TopoDS_Vertex& aV1 = TopoDS::Vertex (myVertices->FindKey (anID1));
Standard_Real aTolV1 = BRep_Tool::Tolerance (aV1);
if (aTolV1 < myVertices->FindFromIndex (anID1))
aTolV1 = myVertices->FindFromIndex (anID1);
gp_Pnt aP1 = BRep_Tool::Pnt (aV1);
const Standard_Integer anID2 = this->myBVHSet1->Element (theID2);
const TopoDS_Vertex& aV2 = TopoDS::Vertex (myVertices->FindKey (anID2));
Standard_Real aTolV2 = BRep_Tool::Tolerance (aV2);
if (aTolV2 < myVertices->FindFromIndex (anID2))
aTolV2 = myVertices->FindFromIndex (anID2);
gp_Pnt aP2 = BRep_Tool::Pnt (aV2);
Standard_Real aTolSum2 = aTolV1 + aTolV2 + myFuzzyValue;
aTolSum2 *= aTolSum2;
Standard_Real aD2 = aP1.SquareDistance (aP2);
if (aD2 < aTolSum2)
{
myPairs.push_back (PairIDs (anID1, anID2));
return Standard_True;
}
}
return Standard_False;
}
protected:
const TopTools_IndexedDataMapOfShapeReal * myVertices;
Standard_Real myFuzzyValue;
};
//
/////////////////////////////////////////////////////////////////////////
//=======================================================================
//function : IntersectVertices
//purpose : Builds the chains of intersecting vertices
//=======================================================================
void BOPAlgo_Tools::IntersectVertices(const TopTools_IndexedDataMapOfShapeReal& theVertices,
const Standard_Real theFuzzyValue,
TopTools_ListOfListOfShape& theChains)
{
Standard_Integer aNbV = theVertices.Extent();
if (aNbV <= 1) {
if (aNbV == 1) {
theChains.Append(TopTools_ListOfShape()).Append(theVertices.FindKey(1));
}
return;
}
// Additional tolerance for intersection
Standard_Real aTolAdd = theFuzzyValue / 2.;
// Use BVH Tree for sorting the vertices
BOPTools_BoxTree aBBTree;
aBBTree.SetSize (aNbV);
for (Standard_Integer i = 1; i <= aNbV; ++i)
{
const TopoDS_Vertex& aV = TopoDS::Vertex(theVertices.FindKey(i));
Standard_Real aTol = BRep_Tool::Tolerance(aV);
if (aTol < theVertices(i))
aTol = theVertices(i);
// Build bnd box for vertex
Bnd_Box aBox;
aBox.Add(BRep_Tool::Pnt(aV));
aBox.SetGap(aTol + aTolAdd);
aBBTree.Add(i, Bnd_Tools::Bnd2BVH(aBox));
}
aBBTree.Build();
// Perform selection of the interfering vertices
BOPAlgo_PairVerticesSelector aPairSelector;
aPairSelector.SetBVHSets (&aBBTree, &aBBTree);
aPairSelector.SetSame (Standard_True);
aPairSelector.SetMapOfVerticesTolerances (theVertices);
aPairSelector.SetFuzzyValue (theFuzzyValue);
aPairSelector.Select();
// Treat the selected pairs
const std::vector<BOPTools_BoxPairSelector::PairIDs>& aPairs = aPairSelector.Pairs();
const Standard_Integer aNbPairs = static_cast<Standard_Integer> (aPairs.size());
// Collect interfering pairs
Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator;
NCollection_IndexedDataMap<Standard_Integer, TColStd_ListOfInteger> aMILI (1, anAlloc);
for (Standard_Integer iPair = 0; iPair < aNbPairs; ++iPair)
{
const BOPTools_BoxPairSelector::PairIDs& aPair = aPairs[iPair];
BOPAlgo_Tools::FillMap<Standard_Integer, TColStd_MapIntegerHasher> (aPair.ID1, aPair.ID2, aMILI, anAlloc);
}
NCollection_List<TColStd_ListOfInteger> aBlocks (anAlloc);
BOPAlgo_Tools::MakeBlocks<Standard_Integer, TColStd_MapIntegerHasher> (aMILI, aBlocks, anAlloc);
NCollection_List<TColStd_ListOfInteger>::Iterator itLI (aBlocks);
for (; itLI.More(); itLI.Next())
{
const TColStd_ListOfInteger& aLI = itLI.Value();
TopTools_ListOfShape &aChain = theChains.Append (TopTools_ListOfShape());
for (TColStd_ListOfInteger::Iterator itI (aLI); itI.More(); itI.Next())
aChain.Append (theVertices.FindKey (itI.Value()));
}
// Add not interfered vertices as a chain of 1 element
for (Standard_Integer i = 1; i <= aNbV; ++i)
{
if (!aMILI.Contains (i))
{
TopTools_ListOfShape &aChain = theChains.Append (TopTools_ListOfShape());
aChain.Append (theVertices.FindKey(i));
}
}
}
//=======================================================================
// Classification of the faces relatively solids
//=======================================================================
//=======================================================================
//class : BOPAlgo_ShapeBox
//purpose : Auxiliary class defining ShapeBox structure
//=======================================================================
class BOPAlgo_ShapeBox
{
public:
//! Empty constructor
BOPAlgo_ShapeBox() {};
//! Sets the shape
void SetShape(const TopoDS_Shape& theS)
{
myShape = theS;
};
//! Returns the shape
const TopoDS_Shape& Shape() const
{
return myShape;
};
//! Sets the bounding box
void SetBox(const Bnd_Box& theBox)
{
myBox = theBox;
};
//! Returns the bounding box
const Bnd_Box& Box() const
{
return myBox;
};
private:
TopoDS_Shape myShape;
Bnd_Box myBox;
};
// Vector of ShapeBox
typedef NCollection_Vector<BOPAlgo_ShapeBox> BOPAlgo_VectorOfShapeBox;
//=======================================================================
//class : BOPAlgo_FillIn3DParts
//purpose : Auxiliary class for faces classification in parallel mode
//=======================================================================
class BOPAlgo_FillIn3DParts : public BOPAlgo_Algo
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor
BOPAlgo_FillIn3DParts()
{
myBBTree = NULL;
myVShapeBox = NULL;
};
//! Destructor
virtual ~BOPAlgo_FillIn3DParts() {};
//! Sets the solid
void SetSolid(const TopoDS_Solid& theSolid)
{
mySolid = theSolid;
};
//! Returns the solid
const TopoDS_Solid& Solid() const
{
return mySolid;
};
//! Sets the box for the solid
void SetBoxS(const Bnd_Box& theBox)
{
myBoxS = theBox;
};
//! Returns the solid's box
const Bnd_Box& BoxS() const
{
return myBoxS;
};
//! Sets own INTERNAL faces of the solid
void SetOwnIF(const TopTools_ListOfShape& theLIF)
{
myOwnIF = theLIF;
};
//! Returns own INTERNAL faces of the solid
const TopTools_ListOfShape& OwnIF() const
{
return myOwnIF;
};
//! Sets the Bounding Box tree
void SetBBTree(BOPTools_BoxTree* theBBTree)
{
myBBTree = theBBTree;
};
//! Sets the ShapeBox structure
void SetShapeBoxVector(const BOPAlgo_VectorOfShapeBox& theShapeBox)
{
myVShapeBox = (BOPAlgo_VectorOfShapeBox*)&theShapeBox;
};
//! Sets the context
void SetContext(const Handle(IntTools_Context)& theContext)
{
myContext = theContext;
}
//! Returns the context
const Handle(IntTools_Context)& Context() const
{
return myContext;
}
//! Performs the classification
virtual void Perform();
//! Returns the faces classified as IN for solid
const TopTools_ListOfShape& InFaces() const
{
return myInFaces;
};
private:
//! Prepares Edge-Face connection map of the given shape
void MapEdgesAndFaces(const TopoDS_Shape& theF,
TopTools_IndexedDataMapOfShapeListOfShape& theEFMap,
const Handle(NCollection_BaseAllocator)& theAlloc);
//! Makes the connexity block of faces using the connection map
void MakeConnexityBlock(const TopoDS_Face& theF,
const TopTools_IndexedMapOfShape& theMEToAvoid,
const TopTools_IndexedDataMapOfShapeListOfShape& theEFMap,
TopTools_MapOfShape& theMFDone,
TopTools_ListOfShape& theLCB,
TopoDS_Face& theFaceToClassify);
TopoDS_Solid mySolid; //! Solid
Bnd_Box myBoxS; // Bounding box of the solid
TopTools_ListOfShape myOwnIF; //! Own INTERNAL faces of the solid
TopTools_ListOfShape myInFaces; //! Faces classified as IN
BOPTools_BoxTree* myBBTree; //! BVH tree of bounding boxes
BOPAlgo_VectorOfShapeBox* myVShapeBox; //! ShapeBoxMap
TopoDS_Iterator myItF; //! Iterators
TopoDS_Iterator myItW;
Handle(IntTools_Context) myContext; //! Context
};
//=======================================================================
//function : BOPAlgo_FillIn3DParts::Perform
//purpose :
//=======================================================================
void BOPAlgo_FillIn3DParts::Perform()
{
BOPAlgo_Algo::UserBreak();
myInFaces.Clear();
// 1. Select boxes of faces that are not out of aBoxS
BOPTools_BoxTreeSelector aSelector;
aSelector.SetBox(Bnd_Tools::Bnd2BVH(myBoxS));
aSelector.SetBVHSet (myBBTree);
//
if (!aSelector.Select())
return;
const TColStd_ListOfInteger& aLIFP = aSelector.Indices();
// 2. Fill maps of edges and faces of the solid
Handle(NCollection_BaseAllocator) anAlloc = new NCollection_IncAllocator;
BOPAlgo_VectorOfShapeBox& aVShapeBox = *myVShapeBox;
TopTools_IndexedMapOfShape aMSE(1, anAlloc), aMSF(1, anAlloc);
TopExp::MapShapes(mySolid, TopAbs_EDGE, aMSE);
TopExp::MapShapes(mySolid, TopAbs_FACE, aMSF);
// Check if the Solid contains any faces
Standard_Boolean bIsEmpty = aMSF.IsEmpty();
// Add own internal faces of the solid into aMSF
TopTools_ListIteratorOfListOfShape aItLS(myOwnIF);
for (; aItLS.More(); aItLS.Next())
aMSF.Add(aItLS.Value());
// 3. aIVec - faces to process.
// Filter the selected faces with faces of the solid.
NCollection_Vector<Standard_Integer> aIVec(256, anAlloc);
TColStd_ListIteratorOfListOfInteger aItLI(aLIFP);
for (; aItLI.More(); aItLI.Next()) {
Standard_Integer nFP = aItLI.Value();
const TopoDS_Shape& aFP = aVShapeBox(nFP).Shape();
if (!aMSF.Contains(aFP))
aIVec.Appended() = nFP;
}
// 4. Classify faces relatively solid.
// Store faces that are IN mySolid into <myInFaces>
Standard_Integer k, aNbFP = aIVec.Length();
// Sort indices if necessary
if (aNbFP > 1)
std::sort(aIVec.begin(), aIVec.end());
if (bIsEmpty)
{
// The solid is empty as it does not contain any faces.
// It could happen when the input solid consists of INTERNAL faces only.
// Classification of any point relatively empty solid would always give IN status.
// Thus, we consider all selected faces as IN without real classification.
for (k = 0; k < aNbFP; ++k)
myInFaces.Append(aVShapeBox(aIVec(k)).Shape());
return;
}
// Prepare EF map of faces to process for building connexity blocks
TopTools_IndexedDataMapOfShapeListOfShape aMEFP(1, anAlloc);
if (aNbFP > 1)
{
for (k = 0; k < aNbFP; ++k)
MapEdgesAndFaces(aVShapeBox(aIVec(k)).Shape(), aMEFP, anAlloc);
}
// Map of Edge-Face connection, necessary for solid classification.
// It will be filled when first classification is performed.
TopTools_IndexedDataMapOfShapeListOfShape aMEFDS(1, anAlloc);
// Fence map to avoid processing of the same faces twice
TopTools_MapOfShape aMFDone(1, anAlloc);
for (k = 0; k < aNbFP; ++k)
{
Standard_Integer nFP = aIVec(k);
const TopoDS_Face& aFP = (*(TopoDS_Face*)&aVShapeBox(nFP).Shape());
if (!aMFDone.Add(aFP))
continue;
// Make connexity blocks of faces, avoiding passing through the
// borders of the solid. It helps to reduce significantly the
// number of classified faces.
TopTools_ListOfShape aLCBF(anAlloc);
// The most appropriate face for classification
TopoDS_Face aFaceToClassify;
MakeConnexityBlock(aFP, aMSE, aMEFP, aMFDone, aLCBF, aFaceToClassify);
if (!myBoxS.IsWhole())
{
// First, try fast classification of the whole block by additional
// check on bounding boxes - check that bounding boxes of all vertices
// of the block interfere with the box of the solid.
// If not, the faces are out.
Standard_Boolean bOut = Standard_False;
aItLS.Initialize(aLCBF);
for (; aItLS.More() && !bOut; aItLS.Next())
{
TopExp_Explorer anExpV(aItLS.Value(), TopAbs_VERTEX);
for (; anExpV.More() && !bOut; anExpV.Next())
{
const TopoDS_Vertex& aV = TopoDS::Vertex(anExpV.Current());
Bnd_Box aBBV;
aBBV.Add(BRep_Tool::Pnt(aV));
aBBV.SetGap(BRep_Tool::Tolerance(aV));
bOut = myBoxS.IsOut(aBBV);
}
}
if (bOut)
continue;
}
if (aFaceToClassify.IsNull())
aFaceToClassify = aFP;
if (aMEFDS.IsEmpty())
// Fill EF map for Solid
TopExp::MapShapesAndAncestors(mySolid, TopAbs_EDGE, TopAbs_FACE, aMEFDS);
// All vertices are interfere with the solids box, run classification.
Standard_Boolean bIsIN = BOPTools_AlgoTools::IsInternalFace
(aFaceToClassify, mySolid, aMEFDS, Precision::Confusion(), myContext);
if (bIsIN)
{
aItLS.Initialize(aLCBF);
for (; aItLS.More(); aItLS.Next())
myInFaces.Append(aItLS.Value());
}
}
}
//=======================================================================
// function: MapEdgesAndFaces
// purpose:
//=======================================================================
void BOPAlgo_FillIn3DParts::MapEdgesAndFaces(const TopoDS_Shape& theF,
TopTools_IndexedDataMapOfShapeListOfShape& theEFMap,
const Handle(NCollection_BaseAllocator)& theAllocator)
{
myItF.Initialize(theF);
for (; myItF.More(); myItF.Next())
{
const TopoDS_Shape& aW = myItF.Value();
if (aW.ShapeType() != TopAbs_WIRE)
continue;
myItW.Initialize(aW);
for (; myItW.More(); myItW.Next())
{
const TopoDS_Shape& aE = myItW.Value();
TopTools_ListOfShape* pLF = theEFMap.ChangeSeek(aE);
if (!pLF)
pLF = &theEFMap(theEFMap.Add(aE, TopTools_ListOfShape(theAllocator)));
pLF->Append(theF);
}
}
}
//=======================================================================
// function: MakeConnexityBlock
// purpose:
//=======================================================================
void BOPAlgo_FillIn3DParts::MakeConnexityBlock(const TopoDS_Face& theFStart,
const TopTools_IndexedMapOfShape& theMEAvoid,
const TopTools_IndexedDataMapOfShapeListOfShape& theEFMap,
TopTools_MapOfShape& theMFDone,
TopTools_ListOfShape& theLCB,
TopoDS_Face& theFaceToClassify)
{
// Add start element
theLCB.Append(theFStart);
if (theEFMap.IsEmpty())
return;
TopTools_ListIteratorOfListOfShape aItCB(theLCB);
for (; aItCB.More(); aItCB.Next())
{
const TopoDS_Shape& aF = aItCB.Value();
myItF.Initialize(aF);
for (; myItF.More(); myItF.Next())
{
const TopoDS_Shape& aW = myItF.Value();
if (aW.ShapeType() != TopAbs_WIRE)
continue;
myItW.Initialize(aW);
for (; myItW.More(); myItW.Next())
{
const TopoDS_Edge& aE = TopoDS::Edge(myItW.Value());
if (theMEAvoid.Contains(aE) || BRep_Tool::Degenerated(aE))
{
if (theFaceToClassify.IsNull())
theFaceToClassify = TopoDS::Face(aF);
continue;
}
const TopTools_ListOfShape* pLF = theEFMap.Seek(aE);
if (!pLF)
continue;
TopTools_ListIteratorOfListOfShape aItLF(*pLF);
for (; aItLF.More(); aItLF.Next())
{
const TopoDS_Shape& aFToAdd = aItLF.Value();
if (theMFDone.Add(aFToAdd))
theLCB.Append(aFToAdd);
}
}
}
}
}
// Vector of solid classifiers
typedef NCollection_Vector<BOPAlgo_FillIn3DParts> BOPAlgo_VectorOfFillIn3DParts;
//=======================================================================
//function : ClassifyFaces
//purpose :
//=======================================================================
void BOPAlgo_Tools::ClassifyFaces(const TopTools_ListOfShape& theFaces,
const TopTools_ListOfShape& theSolids,
const Standard_Boolean theRunParallel,
Handle(IntTools_Context)& theContext,
TopTools_IndexedDataMapOfShapeListOfShape& theInParts,
const TopTools_DataMapOfShapeBox& theShapeBoxMap,
const TopTools_DataMapOfShapeListOfShape& theSolidsIF)
{
Handle(NCollection_BaseAllocator) anAlloc = new NCollection_IncAllocator;
// Fill the vector of shape box with faces and its bounding boxes
BOPAlgo_VectorOfShapeBox aVSB(256, anAlloc);
TopTools_ListIteratorOfListOfShape aItLF(theFaces);
for (; aItLF.More(); aItLF.Next())
{
const TopoDS_Shape& aF = aItLF.Value();
// Append face to the vector of shape box
BOPAlgo_ShapeBox& aSB = aVSB.Appended();
aSB.SetShape(aF);
// Get bounding box for the face
const Bnd_Box* pBox = theShapeBoxMap.Seek(aF);
if (pBox)
aSB.SetBox(*pBox);
else
{
// Build the bounding box
Bnd_Box aBox;
BRepBndLib::Add(aF, aBox);
aSB.SetBox(aBox);
}
}
// Prepare BVH tree of bounding boxes of the faces to classify
// taking the bounding boxes from the just prepared vector
BOPTools_BoxTree aBBTree;
Standard_Integer aNbF = aVSB.Length();
aBBTree.SetSize (aNbF);
for (Standard_Integer i = 0; i < aNbF; ++i)
{
aBBTree.Add(i, Bnd_Tools::Bnd2BVH(aVSB(i).Box()));
}
// Shake tree filler
aBBTree.Build();
// Prepare vector of solids to classify
BOPAlgo_VectorOfFillIn3DParts aVFIP;
TopTools_ListIteratorOfListOfShape aItLS(theSolids);
for (; aItLS.More(); aItLS.Next())
{
const TopoDS_Solid& aSolid = TopoDS::Solid(aItLS.Value());
// Append solid to the vector
BOPAlgo_FillIn3DParts& aFIP = aVFIP.Appended();
aFIP.SetSolid(aSolid);
// Get bounding box for the solid
const Bnd_Box* pBox = theShapeBoxMap.Seek(aSolid);
if (pBox)
aFIP.SetBoxS(*pBox);
else
{
// Build the bounding box
Bnd_Box aBox;
BRepBndLib::Add(aSolid, aBox);
if (!aBox.IsWhole())
{
if (BOPTools_AlgoTools::IsInvertedSolid(aSolid))
aBox.SetWhole();
}
aFIP.SetBoxS(aBox);
}
const TopTools_ListOfShape* pLIF = theSolidsIF.Seek(aSolid);
if (pLIF)
aFIP.SetOwnIF(*pLIF);
aFIP.SetBBTree(&aBBTree);
aFIP.SetShapeBoxVector(aVSB);
}
// Perform classification
//================================================================
BOPTools_Parallel::Perform (theRunParallel, aVFIP, theContext);
//================================================================
// Analyze the results and fill the resulting map
Standard_Integer aNbS = aVFIP.Length();
for (Standard_Integer i = 0; i < aNbS; ++i)
{
BOPAlgo_FillIn3DParts& aFIP = aVFIP(i);
const TopoDS_Shape& aS = aFIP.Solid();
const TopTools_ListOfShape& aLFIn = aFIP.InFaces();
theInParts.Add(aS, aLFIn);
}
}
//=======================================================================
//function : FillInternals
//purpose :
//=======================================================================
void BOPAlgo_Tools::FillInternals(const TopTools_ListOfShape& theSolids,
const TopTools_ListOfShape& theParts,
const TopTools_DataMapOfShapeListOfShape& theImages,
const Handle(IntTools_Context)& theContext)
{
if (theSolids.IsEmpty() || theParts.IsEmpty())
return;
// Map the solids to avoid classification of the own shapes of the solids
TopTools_IndexedMapOfShape aMSSolids;
TopTools_ListOfShape::Iterator itLS(theSolids);
for (; itLS.More(); itLS.Next())
{
const TopoDS_Shape& aSolid = itLS.Value();
if (aSolid.ShapeType() == TopAbs_SOLID)
{
TopExp::MapShapes(aSolid, TopAbs_VERTEX, aMSSolids);
TopExp::MapShapes(aSolid, TopAbs_EDGE, aMSSolids);
TopExp::MapShapes(aSolid, TopAbs_FACE, aMSSolids);
}
}
// Extract BRep elements from the given parts and
// check them for possible splits
TopTools_ListOfShape aLPartsInput = theParts, aLParts;
TopTools_ListOfShape::Iterator itLP(aLPartsInput);
for (; itLP.More(); itLP.Next())
{
const TopoDS_Shape& aPart = itLP.Value();
switch (aPart.ShapeType())
{
case TopAbs_VERTEX:
case TopAbs_EDGE:
case TopAbs_FACE:
{
const TopTools_ListOfShape* pIm = theImages.Seek(aPart);
if (pIm)
{
TopTools_ListOfShape::Iterator itIm(*pIm);
for (; itIm.More(); itIm.Next())
{
const TopoDS_Shape& aPartIm = itIm.Value();
if (!aMSSolids.Contains(aPartIm))
aLParts.Append(aPartIm);
}
}
else if (!aMSSolids.Contains(aPart))
aLParts.Append(aPart);
break;
}
default:
{
for (TopoDS_Iterator it(aPart); it.More(); it.Next())
aLPartsInput.Append(it.Value());
break;
}
}
}
// Classify the given parts relatively solids.
// Add edges and vertices classified as IN into solids instantly,
// and collect faces classified as IN into a list for further shell creation
TopTools_DataMapOfShapeListOfShape anINFaces;
itLS.Initialize(theSolids);
for (; itLS.More(); itLS.Next())
{
const TopoDS_Shape& aSolid = itLS.Value();
if (aSolid.ShapeType() != TopAbs_SOLID)
continue;
TopoDS_Solid aSd = *(TopoDS_Solid*)&aSolid;
itLP.Initialize(aLParts);
for (; itLP.More();)
{
TopoDS_Shape aPart = itLP.Value();
TopAbs_State aState =
BOPTools_AlgoTools::ComputeStateByOnePoint(aPart, aSd, Precision::Confusion(), theContext);
if (aState == TopAbs_IN)
{
if (aPart.ShapeType() == TopAbs_FACE)
{
TopTools_ListOfShape *pFaces = anINFaces.ChangeSeek(aSd);
if (!pFaces)
pFaces = anINFaces.Bound(aSd, TopTools_ListOfShape());
pFaces->Append(aPart);
}
else
{
aPart.Orientation(TopAbs_INTERNAL);
BRep_Builder().Add(aSd, aPart);
}
aLParts.Remove(itLP);
}
else
itLP.Next();
}
}
// Make shells from faces and put them into solids
TopTools_DataMapOfShapeListOfShape::Iterator itM(anINFaces);
for (; itM.More(); itM.Next())
{
TopoDS_Solid aSd = *(TopoDS_Solid*)&itM.Key();
const TopTools_ListOfShape& aFaces = itM.Value();
TopoDS_Compound aCF;
BRep_Builder().MakeCompound(aCF);
TopTools_ListOfShape::Iterator itLF(aFaces);
for (; itLF.More(); itLF.Next())
BRep_Builder().Add(aCF, itLF.Value());
// Build blocks from the faces
TopTools_ListOfShape aLCB;
BOPTools_AlgoTools::MakeConnexityBlocks(aCF, TopAbs_EDGE, TopAbs_FACE, aLCB);
// Build shell from each block
TopTools_ListOfShape::Iterator itCB(aLCB);
for (; itCB.More(); itCB.Next())
{
const TopoDS_Shape& aCB = itCB.Value();
TopoDS_Shell aShell;
BRep_Builder().MakeShell(aShell);
// Add faces of the block to the shell
TopExp_Explorer expF(aCB, TopAbs_FACE);
for (; expF.More(); expF.Next())
{
TopoDS_Face aFInt = TopoDS::Face(expF.Current());
aFInt.Orientation(TopAbs_INTERNAL);
BRep_Builder().Add(aShell, aFInt);
}
BRep_Builder().Add(aSd, aShell);
}
}
}
//=======================================================================
//function : TrsfToPoint
//purpose :
//=======================================================================
Standard_Boolean BOPAlgo_Tools::TrsfToPoint (const Bnd_Box& theBox1,
const Bnd_Box& theBox2,
gp_Trsf& theTrsf,
const gp_Pnt& thePoint,
const Standard_Real theCriteria)
{
// Unify two boxes
Bnd_Box aBox = theBox1;
aBox.Add (theBox2);
gp_XYZ aBCenter = (aBox.CornerMin().XYZ() + aBox.CornerMax().XYZ()) / 2.;
Standard_Real aPBDist = (thePoint.XYZ() - aBCenter).Modulus();
if (aPBDist < theCriteria)
return Standard_False;
Standard_Real aBSize = Sqrt (aBox.SquareExtent());
if ((aBSize / aPBDist) > (1. / theCriteria))
return Standard_False;
theTrsf.SetTranslation (gp_Vec (aBox.CornerMin(), thePoint));
return Standard_True;
}