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_Tools.cxx
msv 977ad98334 0029234: BRepOffsetAPI_NormalProjection produces INTERNAL edges and vertices
Make the algorithm BRepOffsetAPI_NormalProjection use section operation instead of common to get the edge-result of projection to be in face restrictions.

Correct Boolean operation algorithm to produce correctly oriented result in the case of common between face and edge.

The algorithm ShapeUpgrade_UnifySameDomain has been patched to correctly gather same domain faces in a compound.

The TCL script snowflake.tcl has been corrected to get rid of dependence on the order of edges in the result of Boolean operation.
2017-11-14 16:52:41 +03:00

1115 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_Tools.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <gp_Dir.hxx>
#include <gp_Pln.hxx>
#include <gp_Circ.hxx>
#include <gp_Elips.hxx>
#include <gp_Hypr.hxx>
#include <gp_Parab.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <BOPCol_BoxBndTree.hxx>
#include <BOPCol_IndexedMapOfShape.hxx>
#include <BOPCol_IndexedMapOfInteger.hxx>
#include <BOPCol_IndexedDataMapOfShapeListOfShape.hxx>
#include <BOPCol_MapOfShape.hxx>
#include <BOPCol_NCVector.hxx>
#include <BOPCol_Parallel.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepLib.hxx>
#include <BRep_Tool.hxx>
#include <BRep_Builder.hxx>
#include <GeomAPI_ProjectPointOnCurve.hxx>
#include <GeomAPI_ProjectPointOnSurf.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.hxx>
#include <BOPTools_AlgoTools.hxx>
#include <BOPTools_AlgoTools2D.hxx>
#include <NCollection_UBTreeFiller.hxx>
#include <IntTools_Context.hxx>
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 BOPCol_IndexedMapOfShape& theEdges,
TopoDS_Compound& theWires,
const Standard_Boolean theCheckUniquePlane,
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
BOPCol_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,
BOPCol_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)
{
BOPCol_ListOfInteger *pLI = aMPBLI.ChangeSeek(aPB);
if (!pLI) {
pLI = &aMPBLI(aMPBLI.Add(aPB, BOPCol_ListOfInteger(aAllocator)));
}
pLI->Append(nF);
}
//=======================================================================
//function : PerformCommonBlocks
//purpose :
//=======================================================================
void BOPAlgo_Tools::PerformCommonBlocks(BOPDS_IndexedDataMapOfPaveBlockListOfPaveBlock& aMPBLPB,
const Handle(NCollection_BaseAllocator)& aAllocator,
BOPDS_PDS& pDS)
{
Standard_Integer aNbCB;
//
aNbCB=aMPBLPB.Extent();
if (!aNbCB) {
return;
}
//
Handle(BOPDS_CommonBlock) aCB;
NCollection_List<BOPDS_ListOfPaveBlock> aMBlocks(aAllocator);
//
BOPAlgo_Tools::MakeBlocks<Handle(BOPDS_PaveBlock), TColStd_MapTransientHasher>(aMPBLPB, aMBlocks, aAllocator);
//
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>1) {
aCB=new BOPDS_CommonBlock;
aCB->SetPaveBlocks(aLPB);
//
BOPDS_ListIteratorOfListOfPaveBlock aItLPB(aLPB);
for (; aItLPB.More(); aItLPB.Next()) {
pDS->SetCommonBlock(aItLPB.Value(), aCB);
}
}//if (aNbPB>1) {
}
}
//=======================================================================
//function : PerformCommonBlocks
//purpose :
//=======================================================================
void BOPAlgo_Tools::PerformCommonBlocks(const BOPDS_IndexedDataMapOfPaveBlockListOfInteger& aMPBLI,
const Handle(NCollection_BaseAllocator)& ,//aAllocator
BOPDS_PDS& pDS)
{
Standard_Integer nF, i, aNb;
BOPCol_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 BOPCol_ListOfInteger& aLI=aMPBLI.FindFromKey(aPB);
BOPCol_ListOfInteger aNewFaces;
const BOPCol_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
BOPCol_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);
}
}
//=======================================================================
//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 BOPCol_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);
//
// 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 = theContext->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()) {
Standard_Integer nF;
GeomAPI_ProjectPointOnSurf aProjPS;
BOPCol_ListIteratorOfListOfInteger aItLI;
//
aItLI.Initialize(aLFI);
for (; aItLI.More(); aItLI.Next()) {
nF = aItLI.Value();
const TopoDS_Face& aF = *(TopoDS_Face*)&theDS->Shape(nF);
aTol = BRep_Tool::Tolerance(aF);
//
aProjPS = theContext->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
BOPCol_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));
BOPCol_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
BOPCol_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
BOPCol_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);
//
BOPCol_IndexedMapOfShape aMEPln;
aMEPln.Add(aEI);
//
BOPCol_IndexedMapOfShape aMV;
BOPTools::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);
BOPTools::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
BOPCol_ListOfShape aLCBE;
BOPTools_AlgoTools::MakeConnexityBlocks(aCEPln, TopAbs_VERTEX, TopAbs_EDGE, aLCBE);
//
// make wire from each block
BOPCol_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
BOPCol_IndexedDataMapOfShapeListOfShape aDMVE;
BOPTools::MapShapesAndAncestors(aLEdges, TopAbs_VERTEX, TopAbs_EDGE, aDMVE);
//
// find planes for connected edges
Standard_Integer aNbV = aDMVE.Extent();
for (i = 1; i <= aNbV; ++i) {
const BOPCol_ListOfShape& aLEI = aDMVE(i);
if (aLEI.Extent() < 2) {
continue;
}
//
BOPCol_ListIteratorOfListOfShape aItLEI1(aLEI);
for (; aItLEI1.More(); aItLEI1.Next()) {
const TopoDS_Shape& aEI1 = aItLEI1.Value();
const gp_Dir& aDI1 = aDMEdgeTgt.FindFromKey(aEI1);
//
BOPCol_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
BOPCol_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
BOPCol_IndexedMapOfShape aMEAlone, aMEUsed;
BOPTools::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;
BOPCol_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
BOPCol_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);
//
BOPCol_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
BOPCol_ListOfShape aLE;
BOPCol_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 BOPCol_ListOfShape& aLFSp = aBF.Areas();
BOPCol_ListIteratorOfListOfShape aItLF(aLFSp);
for (; aItLF.More(); aItLF.Next()) {
const TopoDS_Shape& aFSp = aItLF.ChangeValue();
aBB.Add(aRFaces, aFSp);
}
}
catch (Standard_Failure) {
continue;
}
}
//
// fix tolerances of the resulting faces
BOPCol_IndexedMapOfShape aMEmpty;
BOPTools_AlgoTools::CorrectTolerances(aRFaces, aMEmpty, 0.05, Standard_False);
BOPTools_AlgoTools::CorrectShapeTolerances(aRFaces, aMEmpty, Standard_False);
//
theFaces = aRFaces;
TopoDS_Iterator aItF(theFaces);
return aItF.More();
}
//=======================================================================
//function : MakeWires
//purpose : Makes wires from the separate blocks of the given edges
//=======================================================================
void MakeWires(const BOPCol_IndexedMapOfShape& theEdges,
TopoDS_Compound& theWires,
const Standard_Boolean theCheckUniquePlane,
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
BOPCol_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));
}
//
BOPCol_ListOfShape aLCBE;
BOPTools_AlgoTools::MakeConnexityBlocks(aCE, TopAbs_VERTEX, TopAbs_EDGE, aLCBE);
//
// make wire from each block
BOPCol_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,
BOPCol_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_TNV
//purpose :
//=======================================================================
class BOPAlgo_TNV;
typedef BOPCol_NCVector
<BOPAlgo_TNV> BOPAlgo_VectorOfTNV;
//
typedef BOPCol_Functor
<BOPAlgo_TNV,
BOPAlgo_VectorOfTNV> BOPAlgo_TNVFunctor;
//
typedef BOPCol_Cnt
<BOPAlgo_TNVFunctor,
BOPAlgo_VectorOfTNV> BOPAlgo_TNVCnt;
//=======================================================================
class BOPAlgo_TNV : public BOPCol_BoxBndTreeSelector{
public:
BOPAlgo_TNV()
: BOPCol_BoxBndTreeSelector(),
myTol (0.), myFuzzyValue(0.), myTree(NULL), myVecTNV(NULL) {
};
//
~BOPAlgo_TNV(){
};
//
void SetVertex(const TopoDS_Vertex& aV) {
myV=aV;
myPnt = BRep_Tool::Pnt(myV);
}
//
const TopoDS_Vertex& Vertex()const {
return myV;
}
//
void SetTree(BOPCol_BoxBndTree& aTree) {
myTree=&aTree;
}
//
void SetTolerance(const Standard_Real theTol) {
myTol = theTol;
}
//
Standard_Real Tolerance() const {
return myTol;
}
//
const gp_Pnt& Pnt() const {
return myPnt;
}
//
void SetFuzzyValue(const Standard_Real theFuzzyValue) {
myFuzzyValue = theFuzzyValue;
}
//
void SetVectorOfTNV(const BOPAlgo_VectorOfTNV& theVec) {
myVecTNV = &theVec;
}
//
virtual Standard_Boolean Accept(const Standard_Integer& theIndex)
{
const BOPAlgo_TNV& aTNV = myVecTNV->Value(theIndex - 1);
Standard_Real aTolSum2 = myTol + aTNV.Tolerance() + myFuzzyValue;
aTolSum2 *= aTolSum2;
Standard_Real aD2 = myPnt.SquareDistance(aTNV.Pnt());
if (aD2 < aTolSum2)
return BOPCol_BoxBndTreeSelector::Accept(theIndex);
return Standard_False;
}
//
void Perform() {
myTree->Select(*this);
}
//
protected:
Standard_Real myTol;
Standard_Real myFuzzyValue;
gp_Pnt myPnt;
TopoDS_Vertex myV;
BOPCol_BoxBndTree *myTree;
const BOPAlgo_VectorOfTNV *myVecTNV;
};
//
/////////////////////////////////////////////////////////////////////////
//=======================================================================
//function : IntersectVertices
//purpose : Builds the chains of intersecting vertices
//=======================================================================
void BOPAlgo_Tools::IntersectVertices(const BOPCol_IndexedDataMapOfShapeReal& theVertices,
const Standard_Boolean theRunParallel,
const Standard_Real theFuzzyValue,
BOPCol_ListOfListOfShape& theChains)
{
Standard_Integer i, j, aNbV = theVertices.Extent();
if (aNbV <= 1) {
if (aNbV == 1) {
theChains.Append(BOPCol_ListOfShape()).Append(theVertices.FindKey(1));
}
return;
}
//
// Use unbalanced binary tree of bounding boxes for sorting of the vertices.
BOPCol_BoxBndTree aBBTree;
NCollection_UBTreeFiller <Standard_Integer,
Bnd_Box> aTreeFiller(aBBTree);
// Perform intersection of the vertices
BOPAlgo_VectorOfTNV aVTNV;
//
// Use additional tolerance for intersection
Standard_Real aTolAdd = theFuzzyValue / 2.;
// Prepare the tree
for (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);
//
aTreeFiller.Add(i, aBox);
//
BOPAlgo_TNV& aTNV=aVTNV.Append1();
aTNV.SetTree(aBBTree);
aTNV.SetBox(aBox);
aTNV.SetVertex(aV);
aTNV.SetTolerance(aTol);
aTNV.SetFuzzyValue(theFuzzyValue);
aTNV.SetVectorOfTNV(aVTNV);
}
// Shake the tree
aTreeFiller.Fill();
//
// Perform intersection
BOPAlgo_TNVCnt::Perform(theRunParallel, aVTNV);
//
// Fence map
BOPCol_MapOfInteger aMFence;
// Build chains of intersecting vertices
for (i = 1; i <= aNbV; ++i) {
if (!aMFence.Add(i)) {
continue;
}
// Start the chain
BOPCol_IndexedMapOfInteger aMChain;
aMChain.Add(i);
//
for (j = 1; j <= aMChain.Extent(); ++j) {
BOPAlgo_TNV& aTNV = aVTNV(aMChain(j) - 1);
const BOPCol_ListOfInteger& aLI = aTNV.Indices();
// Add these vertices into the chain
for (BOPCol_ListIteratorOfListOfInteger aItLI(aLI); aItLI.More(); aItLI.Next()) {
if (aMFence.Add(aItLI.Value())) {
aMChain.Add(aItLI.Value());
}
}
}
//
// Put vertices of the chain into the list
BOPCol_ListOfShape& aChain = theChains.Append(BOPCol_ListOfShape());
//
Standard_Integer aNbVChain = aMChain.Extent();
for (j = 1; j <= aNbVChain; ++j) {
const TopoDS_Vertex& aVP = aVTNV(aMChain(j) - 1).Vertex();
aChain.Append(aVP);
}
}
}
//=======================================================================
//function : TreatCompound
//purpose :
//=======================================================================
void BOPAlgo_Tools::TreatCompound(const TopoDS_Shape& theS,
BOPCol_MapOfShape& aMFence,
BOPCol_ListOfShape& theLS)
{
TopAbs_ShapeEnum aType = theS.ShapeType();
if (aType != TopAbs_COMPOUND)
{
if (aMFence.Add(theS))
theLS.Append(theS);
return;
}
TopoDS_Iterator aIt(theS);
for (; aIt.More(); aIt.Next())
{
const TopoDS_Shape& aS = aIt.Value();
TreatCompound(aS, aMFence, theLS);
}
}