1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-04 18:06:22 +03:00
occt/src/BOPAlgo/BOPAlgo_PaveFiller_3.cxx
emv d3578357e3 0029711: General Fuse operation produces invalid result
The following improvements have been introduced in Boolean Operations algorithm s:
1. UBTree is replaced with EBTree in Boolean operations to be able to add/remove elements into the tree of bounding boxes.
2. Repeated (nested) intersection of sub-shapes is performed with argument vertices whose tolerances increased during the operation.
3. The algorithms of Edge/Edge and Edge/Face intersection have been improved for the cases when the intersection point is located close to the edge boundaries .
4. New procedure has been implemented to ensure forced creation of Edge/Face common blocks in cases when the edge is really close to the face.
5. Post-processing of Face/Face intersection results has been improved.
6. Extension of the planar faces for Plane/Plane intersection is avoided.
7. Builder Face now better classifies potentially internal edges relatively to new faces with filtering by bounding boxes.

Side effect changes:
1. IntTools_ShrunkRange now keeps the length of the valid range of the edge.
2. The method BOPDS_DS::UpdateEdgeTolerance() has been removed as unused (replaced by the BOPAlgo_PaveFiller::UpdateEdgeTolerance()).

Test case for the issue 0029900.
Test case for the issue 0029711.
Adjustments of the existing test cases.

Avoid using uninitialized variables.
2018-07-27 16:19:15 +03:00

1118 lines
37 KiB
C++

// Created by: Peter KURNEV
// Copyright (c) 2010-2014 OPEN CASCADE SAS
// Copyright (c) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
// Copyright (c) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, CEDRAT,
// EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Bnd_Box.hxx>
#include <BOPAlgo_PaveFiller.hxx>
#include <BOPAlgo_Tools.hxx>
#include <BOPAlgo_Alerts.hxx>
#include <BOPDS_CommonBlock.hxx>
#include <BOPDS_CoupleOfPaveBlocks.hxx>
#include <BOPDS_DS.hxx>
#include <BOPDS_Interf.hxx>
#include <BOPDS_Iterator.hxx>
#include <BOPDS_MapOfPaveBlock.hxx>
#include <BOPDS_Pave.hxx>
#include <BOPDS_PaveBlock.hxx>
#include <BOPDS_VectorOfInterfEE.hxx>
#include <BOPTools_AlgoTools.hxx>
#include <BOPTools_AlgoTools2D.hxx>
#include <BOPTools_Parallel.hxx>
#include <BndLib_Add3dCurve.hxx>
#include <BRep_Tool.hxx>
#include <BRep_Builder.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <GeomAPI_ProjectPointOnCurve.hxx>
#include <gp_Pnt.hxx>
#include <IntTools_CommonPrt.hxx>
#include <IntTools_Context.hxx>
#include <IntTools_EdgeEdge.hxx>
#include <IntTools_Range.hxx>
#include <IntTools_SequenceOfCommonPrts.hxx>
#include <IntTools_SequenceOfRanges.hxx>
#include <IntTools_ShrunkRange.hxx>
#include <IntTools_Tools.hxx>
#include <NCollection_IncAllocator.hxx>
#include <NCollection_Vector.hxx>
#include <Precision.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Vertex.hxx>
/////////////////////////////////////////////////////////////////////////
//=======================================================================
//class : BOPAlgo_EdgeEdge
//purpose :
//=======================================================================
class BOPAlgo_EdgeEdge :
public IntTools_EdgeEdge,
public BOPAlgo_Algo {
public:
DEFINE_STANDARD_ALLOC
//
BOPAlgo_EdgeEdge():
IntTools_EdgeEdge(),
BOPAlgo_Algo() {
};
//
virtual ~BOPAlgo_EdgeEdge(){
};
//
void SetPaveBlock1(const Handle(BOPDS_PaveBlock)& aPB) {
myPB1=aPB;
}
//
Handle(BOPDS_PaveBlock)& PaveBlock1() {
return myPB1;
}
//
void SetPaveBlock2(const Handle(BOPDS_PaveBlock)& aPB) {
myPB2=aPB;
}
//
Handle(BOPDS_PaveBlock)& PaveBlock2() {
return myPB2;
}
//
void SetFuzzyValue(const Standard_Real theFuzz) {
IntTools_EdgeEdge::SetFuzzyValue(theFuzz);
}
//
virtual void Perform() {
BOPAlgo_Algo::UserBreak();
try
{
OCC_CATCH_SIGNALS
IntTools_EdgeEdge::Perform();
}
catch (Standard_Failure)
{
AddError(new BOPAlgo_AlertIntersectionFailed);
}
}
//
protected:
Handle(BOPDS_PaveBlock) myPB1;
Handle(BOPDS_PaveBlock) myPB2;
};
//
//=======================================================================
typedef NCollection_Vector
<BOPAlgo_EdgeEdge> BOPAlgo_VectorOfEdgeEdge;
//
typedef BOPTools_Functor
<BOPAlgo_EdgeEdge,
BOPAlgo_VectorOfEdgeEdge> BOPAlgo_EdgeEdgeFunctor;
//
typedef BOPTools_Cnt
<BOPAlgo_EdgeEdgeFunctor,
BOPAlgo_VectorOfEdgeEdge> BOPAlgo_EdgeEdgeCnt;
//
/////////////////////////////////////////////////////////////////////////
//=======================================================================
// function: PerformEE
// purpose:
//=======================================================================
void BOPAlgo_PaveFiller::PerformEE()
{
FillShrunkData(TopAbs_EDGE, TopAbs_EDGE);
//
myIterator->Initialize(TopAbs_EDGE, TopAbs_EDGE);
Standard_Integer iSize = myIterator->ExpectedLength();
if (!iSize) {
return;
}
//
Standard_Boolean bExpressCompute, bIsPBSplittable1, bIsPBSplittable2;
Standard_Integer i, iX, nE1, nE2, aNbCPrts, k, aNbEdgeEdge;
Standard_Integer nV11, nV12, nV21, nV22;
Standard_Real aTS11, aTS12, aTS21, aTS22, aT11, aT12, aT21, aT22;
TopAbs_ShapeEnum aType;
BOPDS_ListIteratorOfListOfPaveBlock aIt1, aIt2;
Handle(NCollection_BaseAllocator) aAllocator;
BOPAlgo_VectorOfEdgeEdge aVEdgeEdge;
BOPDS_MapIteratorOfMapOfPaveBlock aItPB;
// keep modified edges for further update
TColStd_MapOfInteger aMEdges;
//
aAllocator=NCollection_BaseAllocator::CommonBaseAllocator();
//-----------------------------------------------------scope f
BOPDS_IndexedDataMapOfPaveBlockListOfPaveBlock aMPBLPB(100, aAllocator);
BOPDS_IndexedDataMapOfShapeCoupleOfPaveBlocks aMVCPB(100, aAllocator);
BOPAlgo_DataMapOfPaveBlockBndBox aDMPBBox(100, aAllocator);
//
BOPDS_VectorOfInterfEE& aEEs=myDS->InterfEE();
aEEs.SetIncrement(iSize);
//
for (; myIterator->More(); myIterator->Next()) {
myIterator->Value(nE1, nE2);
//
const BOPDS_ShapeInfo& aSIE1=myDS->ShapeInfo(nE1);
if (aSIE1.HasFlag()){
continue;
}
const BOPDS_ShapeInfo& aSIE2=myDS->ShapeInfo(nE2);
if (aSIE2.HasFlag()){
continue;
}
//
BOPDS_ListOfPaveBlock& aLPB1 = myDS->ChangePaveBlocks(nE1);
if (aLPB1.IsEmpty()) {
continue;
}
//
BOPDS_ListOfPaveBlock& aLPB2 = myDS->ChangePaveBlocks(nE2);
if (aLPB2.IsEmpty()) {
continue;
}
//
const TopoDS_Edge& aE1=(*(TopoDS_Edge *)(&aSIE1.Shape()));
const TopoDS_Edge& aE2=(*(TopoDS_Edge *)(&aSIE2.Shape()));
//
aIt1.Initialize(aLPB1);
for (; aIt1.More(); aIt1.Next()) {
Bnd_Box aBB1;
//
Handle(BOPDS_PaveBlock)& aPB1=aIt1.ChangeValue();
//
if (!GetPBBox(aE1, aPB1, aDMPBBox, aT11, aT12, aTS11, aTS12, aBB1)) {
continue;
}
//
aPB1->Indices(nV11, nV12);
//
aIt2.Initialize(aLPB2);
for (; aIt2.More(); aIt2.Next()) {
Bnd_Box aBB2;
//
Handle(BOPDS_PaveBlock)& aPB2=aIt2.ChangeValue();
//
if (!GetPBBox(aE2, aPB2, aDMPBBox, aT21, aT22, aTS21, aTS22, aBB2)) {
continue;
}
//
if (aBB1.IsOut(aBB2)) {
continue;
}
//
aPB2->Indices(nV21, nV22);
//
bExpressCompute=((nV11==nV21 && nV12==nV22) ||
(nV12==nV21 && nV11==nV22));
//
BOPAlgo_EdgeEdge& anEdgeEdge=aVEdgeEdge.Appended();
//
anEdgeEdge.UseQuickCoincidenceCheck(bExpressCompute);
//
anEdgeEdge.SetPaveBlock1(aPB1);
anEdgeEdge.SetPaveBlock2(aPB2);
//
anEdgeEdge.SetEdge1(aE1, aT11, aT12);
anEdgeEdge.SetEdge2(aE2, aT21, aT22);
anEdgeEdge.SetFuzzyValue(myFuzzyValue);
anEdgeEdge.SetProgressIndicator(myProgressIndicator);
}//for (; aIt2.More(); aIt2.Next()) {
}//for (; aIt1.More(); aIt1.Next()) {
}//for (; myIterator->More(); myIterator->Next()) {
//
aNbEdgeEdge=aVEdgeEdge.Length();
//======================================================
BOPAlgo_EdgeEdgeCnt::Perform(myRunParallel, aVEdgeEdge);
//======================================================
//
for (k = 0; k < aNbEdgeEdge; ++k) {
Bnd_Box aBB1, aBB2;
//
BOPAlgo_EdgeEdge& anEdgeEdge=aVEdgeEdge(k);
if (!anEdgeEdge.IsDone() || anEdgeEdge.HasErrors()) {
// Warn about failed intersection of sub-shapes
const TopoDS_Shape& aE1 = myDS->Shape(anEdgeEdge.PaveBlock1()->OriginalEdge());
const TopoDS_Shape& aE2 = myDS->Shape(anEdgeEdge.PaveBlock2()->OriginalEdge());
AddIntersectionFailedWarning(aE1, aE2);
continue;
}
//
const IntTools_SequenceOfCommonPrts& aCPrts = anEdgeEdge.CommonParts();
aNbCPrts = aCPrts.Length();
if (!aNbCPrts) {
continue;
}
//--------------------------------------------
Handle(BOPDS_PaveBlock)& aPB1=anEdgeEdge.PaveBlock1();
nE1=aPB1->OriginalEdge();
aPB1->Range(aT11, aT12);
if (!aPB1->HasShrunkData()) {
aTS11 = aT11;
aTS12 = aT12;
bIsPBSplittable1 = Standard_False;
}
else {
aPB1->ShrunkData(aTS11, aTS12, aBB1, bIsPBSplittable1);
}
//
Handle(BOPDS_PaveBlock)& aPB2=anEdgeEdge.PaveBlock2();
nE2=aPB2->OriginalEdge();
aPB2->Range(aT21, aT22);
if (!aPB2->HasShrunkData()) {
aTS21 = aT21;
aTS22 = aT22;
bIsPBSplittable2 = Standard_False;
}
else {
aPB2->ShrunkData(aTS21, aTS22, aBB2, bIsPBSplittable2);
}
//
//--------------------------------------------
IntTools_Range aR11(aT11, aTS11), aR12(aTS12, aT12),
aR21(aT21, aTS21), aR22(aTS22, aT22);
//
Standard_Boolean bAnalytical = Standard_False;
{
const TopoDS_Edge& aOE1 = *(TopoDS_Edge*)&myDS->Shape(nE1);
const TopoDS_Edge& aOE2 = *(TopoDS_Edge*)&myDS->Shape(nE2);
//
BRepAdaptor_Curve aBAC1(aOE1), aBAC2(aOE2);
//
GeomAbs_CurveType aType1 = aBAC1.GetType();
GeomAbs_CurveType aType2 = aBAC2.GetType();
//
bAnalytical = (((aType1 == GeomAbs_Line) &&
(aType2 == GeomAbs_Line ||
aType2 == GeomAbs_Circle)) ||
((aType2 == GeomAbs_Line) &&
(aType1 == GeomAbs_Line ||
aType1 == GeomAbs_Circle)));
}
//
for (i=1; i<=aNbCPrts; ++i) {
const IntTools_CommonPrt& aCPart=aCPrts(i);
//
const TopoDS_Edge& aE1=aCPart.Edge1();
const TopoDS_Edge& aE2=aCPart.Edge2();
//
aType=aCPart.Type();
switch (aType) {
case TopAbs_VERTEX: {
if (!bIsPBSplittable1 || !bIsPBSplittable2) {
continue;
}
//
Standard_Boolean bIsOnPave[4];
Standard_Integer nV[4], j;
Standard_Real aT1, aT2, aTol;
TopoDS_Vertex aVnew;
IntTools_Range aCR1, aCR2;
//
IntTools_Tools::VertexParameters(aCPart, aT1, aT2);
aTol = Precision::Confusion();
aCR1 = aCPart.Range1();
aCR2 = aCPart.Ranges2()(1);
//
//decide to keep the pave or not
bIsOnPave[0] = IntTools_Tools::IsOnPave1(aT1, aR11, aTol) ||
IntTools_Tools::IsOnPave1(aR11.First(), aCR1, aTol);
bIsOnPave[1] = IntTools_Tools::IsOnPave1(aT1, aR12, aTol) ||
IntTools_Tools::IsOnPave1(aR12.Last(), aCR1, aTol);
bIsOnPave[2] = IntTools_Tools::IsOnPave1(aT2, aR21, aTol) ||
IntTools_Tools::IsOnPave1(aR21.First(), aCR2, aTol);
bIsOnPave[3] = IntTools_Tools::IsOnPave1(aT2, aR22, aTol) ||
IntTools_Tools::IsOnPave1(aR22.Last(), aCR2, aTol);
//
aPB1->Indices(nV[0], nV[1]);
aPB2->Indices(nV[2], nV[3]);
//
if((bIsOnPave[0] && bIsOnPave[2]) ||
(bIsOnPave[0] && bIsOnPave[3]) ||
(bIsOnPave[1] && bIsOnPave[2]) ||
(bIsOnPave[1] && bIsOnPave[3])) {
continue;
}
//
Standard_Boolean isVExists = Standard_False;
for (j = 0; j < 4; ++j)
{
if (bIsOnPave[j])
{
Handle(BOPDS_PaveBlock)& aPB = (j < 2) ? aPB2 : aPB1;
bIsOnPave[j] = ForceInterfVE(nV[j], aPB, aMEdges);
if (bIsOnPave[j]) isVExists = Standard_True;
}
}
BOPTools_AlgoTools::MakeNewVertex(aE1, aT1, aE2, aT2, aVnew);
const gp_Pnt aPnew = BRep_Tool::Pnt(aVnew);
if (isVExists)
{
// The found intersection point is located closely to one of the
// pave blocks bounds. So, do not create the new vertex in this point.
// Check if this point is a real intersection point or just a touching point.
// If it is a touching point, do nothing.
// If it is an intersection point, update the existing vertex to cover the
// intersection point.
const gp_Pnt aPOnE1 = BRepAdaptor_Curve(aE1).Value(aT1);
const gp_Pnt aPOnE2 = BRepAdaptor_Curve(aE2).Value(aT2);
if (aPOnE1.Distance(aPOnE2) > Precision::Intersection())
// No intersection point
continue;
// Real intersection is present.
// Update the existing vertex to cover the intersection point.
for (j = 0; j < 4; ++j)
{
if (bIsOnPave[j])
{
const TopoDS_Vertex& aV = TopoDS::Vertex(myDS->Shape(nV[j]));
const gp_Pnt aP = BRep_Tool::Pnt(aV);
Standard_Real aDistPP = aP.Distance(aPnew);
// Just update the vertex
UpdateVertex(nV[j], aDistPP);
myVertsToAvoidExtension.Add(nV[j]);
}
}
}
Standard_Real aTolVnew = BRep_Tool::Tolerance(aVnew);
if (bAnalytical) {
// increase tolerance for Line/Line intersection, but do not update
// the vertex till its intersection with some other shape
Standard_Real aTolMin = (BRepAdaptor_Curve(aE1).GetType() == GeomAbs_Line) ?
(aCR1.Last() - aCR1.First()) / 2. : (aCR2.Last() - aCR2.First()) / 2.;
if (aTolMin > aTolVnew) {
aTolVnew = aTolMin;
}
}
// <-LXBR
{
Standard_Integer nVS[2], iFound;
Standard_Real aTolVx, aD2, aDT2;
TColStd_MapOfInteger aMV;
gp_Pnt aPx;
//
iFound=0;
j=-1;
aMV.Add(nV[0]);
aMV.Add(nV[1]);
//
if (aMV.Contains(nV[2])) {
++j;
nVS[j]=nV[2];
}
if (aMV.Contains(nV[3])) {
++j;
nVS[j]=nV[3];
}
//
for (Standard_Integer k1=0; k1<=j; ++k1) {
const TopoDS_Vertex& aVx= *(TopoDS_Vertex*)&(myDS->Shape(nVS[k1]));
aTolVx=BRep_Tool::Tolerance(aVx);
aPx=BRep_Tool::Pnt(aVx);
aD2=aPnew.SquareDistance(aPx);
//
aDT2=100.*(aTolVnew+aTolVx)*(aTolVnew+aTolVx);
//
if (aD2<aDT2) {
iFound=1;
break;
}
}
//
if (iFound) {
continue;
}
}
//
// 1
BOPDS_InterfEE& aEE=aEEs.Appended();
iX=aEEs.Length()-1;
aEE.SetIndices(nE1, nE2);
aEE.SetCommonPart(aCPart);
// 2
myDS->AddInterf(nE1, nE2);
//
BOPDS_CoupleOfPaveBlocks aCPB;
//
aCPB.SetPaveBlocks(aPB1, aPB2);
aCPB.SetIndexInterf(iX);
aCPB.SetTolerance(aTolVnew);
aMVCPB.Add(aVnew, aCPB);
}//case TopAbs_VERTEX:
break;
//
case TopAbs_EDGE: {
if (aNbCPrts > 1) {
break;
}
//
Standard_Boolean bHasSameBounds;
bHasSameBounds=aPB1->HasSameBounds(aPB2);
if (!bHasSameBounds) {
break;
}
// 1
BOPDS_InterfEE& aEE=aEEs.Appended();
iX=aEEs.Length()-1;
aEE.SetIndices(nE1, nE2);
aEE.SetCommonPart(aCPart);
// 2
myDS->AddInterf(nE1, nE2);
//
BOPAlgo_Tools::FillMap<Handle(BOPDS_PaveBlock), TColStd_MapTransientHasher>(aPB1, aPB2, aMPBLPB, aAllocator);
}//case TopAbs_EDGE
break;
default:
break;
}//switch (aType) {
}//for (i=1; i<=aNbCPrts; i++) {
}//for (k=0; k < aNbFdgeEdge; ++k) {
//
//=========================================
// post treatment
//=========================================
BOPAlgo_Tools::PerformCommonBlocks(aMPBLPB, aAllocator, myDS, myContext);
// Update vertices of common blocks with real CB tolerances
UpdateVerticesOfCB();
PerformNewVertices(aMVCPB, aAllocator);
//
if (aMEdges.Extent()) {
Standard_Integer aNbV = aMVCPB.Extent();
for (i = 1; i <= aNbV; ++i) {
Handle(BOPDS_PaveBlock) aPB1, aPB2;
const BOPDS_CoupleOfPaveBlocks& aCPB = aMVCPB.FindFromIndex(i);
aCPB.PaveBlocks(aPB1, aPB2);
//
aMEdges.Remove(aPB1->OriginalEdge());
aMEdges.Remove(aPB2->OriginalEdge());
}
//
SplitPaveBlocks(aMEdges, Standard_False);
}
//
//-----------------------------------------------------scope t
aMPBLPB.Clear();
aMVCPB.Clear();
}
//=======================================================================
//function : PerformVerticesEE
//purpose :
//=======================================================================
void BOPAlgo_PaveFiller::PerformNewVertices
(BOPDS_IndexedDataMapOfShapeCoupleOfPaveBlocks& theMVCPB,
const Handle(NCollection_BaseAllocator)& theAllocator,
const Standard_Boolean bIsEEIntersection)
{
Standard_Integer aNbV = theMVCPB.Extent();
if (!aNbV) {
return;
}
//
Standard_Real aTolAdd = myFuzzyValue / 2.;
//
// 1. Fuse the new vertices
TopTools_IndexedDataMapOfShapeListOfShape aImages;
TreatNewVertices(theMVCPB, aImages);
//
// 2. Add new vertices to myDS and connect indices to CPB structure
BOPDS_VectorOfInterfEE& aEEs = myDS->InterfEE();
BOPDS_VectorOfInterfEF& aEFs = myDS->InterfEF();
//
Standard_Integer i, aNb = aImages.Extent();
for (i = 1; i <= aNb; ++i) {
const TopoDS_Vertex& aV = TopoDS::Vertex(aImages.FindKey(i));
const TopTools_ListOfShape& aLVSD = aImages.FindFromIndex(i);
//
BOPDS_ShapeInfo aSI;
aSI.SetShapeType(TopAbs_VERTEX);
aSI.SetShape(aV);
Standard_Integer iV = myDS->Append(aSI);
//
BOPDS_ShapeInfo& aSIDS = myDS->ChangeShapeInfo(iV);
Bnd_Box& aBox = aSIDS.ChangeBox();
aBox.Add(BRep_Tool::Pnt(aV));
aBox.SetGap(BRep_Tool::Tolerance(aV) + aTolAdd);
//
TopTools_ListIteratorOfListOfShape aItLS(aLVSD);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aVx = aItLS.Value();
BOPDS_CoupleOfPaveBlocks &aCPB = theMVCPB.ChangeFromKey(aVx);
aCPB.SetIndex(iV);
// update interference
Standard_Integer iX = aCPB.IndexInterf();
BOPDS_Interf *aInt = bIsEEIntersection ? (BOPDS_Interf*)(&aEEs(iX)) : (BOPDS_Interf*) (&aEFs(iX));
aInt->SetIndexNew(iV);
}
}
//
// 3. Map PaveBlock/ListOfVertices to add to this PaveBlock ->aMPBLI
BOPDS_IndexedDataMapOfPaveBlockListOfInteger aMPBLI(100, theAllocator);
for (i = 1; i <= aNbV; ++i) {
const BOPDS_CoupleOfPaveBlocks& aCPB = theMVCPB.FindFromIndex(i);
Standard_Integer iV = aCPB.Index();
//
Handle(BOPDS_PaveBlock) aPB[2];
aCPB.PaveBlocks(aPB[0], aPB[1]);
for (Standard_Integer j = 0; j < 2; ++j) {
TColStd_ListOfInteger *pLI = aMPBLI.ChangeSeek(aPB[j]);
if (!pLI) {
pLI = &aMPBLI(aMPBLI.Add(aPB[j], TColStd_ListOfInteger(theAllocator)));
}
pLI->Append(iV);
//
if (aPB[0] == aPB[1]) {
break;
}
}
}
//
// 4. Compute Extra Paves and split Pave blocks by the Extra paves
IntersectVE(aMPBLI, Standard_False);
}
//=======================================================================
//function : TreatNewVertices
//purpose :
//=======================================================================
void BOPAlgo_PaveFiller::TreatNewVertices
(const BOPDS_IndexedDataMapOfShapeCoupleOfPaveBlocks& theMVCPB,
TopTools_IndexedDataMapOfShapeListOfShape& myImages)
{
//
// Prepare for intersection
TopTools_IndexedDataMapOfShapeReal aVerts;
Standard_Integer i, aNbV = theMVCPB.Extent();
for (i = 1; i <= aNbV; ++i) {
const TopoDS_Shape& aV = theMVCPB.FindKey(i);
Standard_Real aTol = theMVCPB.FindFromIndex(i).Tolerance();
aVerts.Add(aV, aTol);
}
//
// Perform intersection
TopTools_ListOfListOfShape aChains;
BOPAlgo_Tools::IntersectVertices(aVerts, myRunParallel, myFuzzyValue, aChains);
//
// Treat the results - make new vertices for each chain
TopTools_ListOfListOfShape::Iterator aItC(aChains);
for (; aItC.More(); aItC.Next()) {
const TopTools_ListOfShape& aLVSD = aItC.Value();
//
TopoDS_Vertex aVNew;
BOPTools_AlgoTools::MakeVertex(aLVSD, aVNew);
myImages.Add(aVNew, aLVSD);
}
}
//=======================================================================
//function : FillShrunkData
//purpose :
//=======================================================================
void BOPAlgo_PaveFiller::FillShrunkData(Handle(BOPDS_PaveBlock)& thePB)
{
// Vertices
Standard_Integer nV1, nV2;
thePB->Indices(nV1, nV2);
const TopoDS_Vertex& aV1=(*(TopoDS_Vertex *)(&myDS->Shape(nV1)));
const TopoDS_Vertex& aV2=(*(TopoDS_Vertex *)(&myDS->Shape(nV2)));
// Get the edge
Standard_Integer nE = thePB->OriginalEdge();
if (nE < 0 && !thePB->HasEdge(nE))
return;
const TopoDS_Edge& aE=(*(TopoDS_Edge *)(&myDS->Shape(nE)));
// Range
Standard_Real aT1, aT2;
thePB->Range(aT1, aT2);
//
IntTools_ShrunkRange aSR;
aSR.SetContext(myContext);
aSR.SetData(aE, aT1, aT2, aV1, aV2);
aSR.Perform();
// Analyze the results of computations
AnalyzeShrunkData(thePB, aSR);
}
//=======================================================================
// function: AnalyzeShrunkData
// purpose:
//=======================================================================
void BOPAlgo_PaveFiller::AnalyzeShrunkData(const Handle(BOPDS_PaveBlock)& thePB,
const IntTools_ShrunkRange& theSR)
{
// in case of error treat the warning status
Standard_Boolean bWholeEdge = Standard_False;
TopoDS_Shape aWarnShape;
//
if (!theSR.IsDone() || !theSR.IsSplittable()) {
Standard_Real aEFirst, aELast, aPBFirst, aPBLast;
BRep_Tool::Range(theSR.Edge(), aEFirst, aELast);
thePB->Range(aPBFirst, aPBLast);
bWholeEdge = !(aPBFirst > aEFirst || aPBLast < aELast);
if (bWholeEdge && thePB->OriginalEdge() >= 0) {
aWarnShape = theSR.Edge();
}
else {
const TopoDS_Shape& aV1 = myDS->Shape(thePB->Pave1().Index());
const TopoDS_Shape& aV2 = myDS->Shape(thePB->Pave2().Index());
BRep_Builder().MakeCompound(TopoDS::Compound(aWarnShape));
BRep_Builder().Add(aWarnShape, theSR.Edge());
BRep_Builder().Add(aWarnShape, aV1);
BRep_Builder().Add(aWarnShape, aV2);
}
//
if (!theSR.IsDone()) {
if (bWholeEdge)
AddWarning (new BOPAlgo_AlertTooSmallEdge (aWarnShape));
else
AddWarning (new BOPAlgo_AlertBadPositioning (aWarnShape));
Standard_Real aTS1, aTS2;
theSR.ShrunkRange(aTS1, aTS2);
thePB->SetShrunkData(aTS1, aTS2, Bnd_Box(), Standard_False);
return;
}
//
if (bWholeEdge)
AddWarning (new BOPAlgo_AlertNotSplittableEdge (aWarnShape));
else
AddWarning (new BOPAlgo_AlertBadPositioning (aWarnShape));
}
//
Standard_Real aTS1, aTS2;
theSR.ShrunkRange(aTS1, aTS2);
Bnd_Box aBox = theSR.BndBox();
aBox.SetGap(aBox.GetGap() + myFuzzyValue / 2.);
thePB->SetShrunkData(aTS1, aTS2, aBox, theSR.IsSplittable());
}
//=======================================================================
//function : ForceInterfVE
//purpose :
//=======================================================================
Standard_Boolean BOPAlgo_PaveFiller::ForceInterfVE(const Standard_Integer nV,
Handle(BOPDS_PaveBlock)& aPB,
TColStd_MapOfInteger& theMEdges)
{
Standard_Integer nE, nVx, nVSD, iFlag;
Standard_Real aT, aTolVNew;
//
nE = aPB->OriginalEdge();
//
const BOPDS_ShapeInfo& aSIE=myDS->ShapeInfo(nE);
if (aSIE.HasSubShape(nV)) {
return Standard_True;
}
//
if (myDS->HasInterf(nV, nE)) {
return Standard_True;
}
//
if (myDS->HasInterfShapeSubShapes(nV, nE)) {
return Standard_True;
}
//
if (aPB->Pave1().Index() == nV ||
aPB->Pave2().Index() == nV) {
return Standard_True;
}
//
nVx = nV;
if (myDS->HasShapeSD(nV, nVSD)) {
nVx = nVSD;
}
//
const TopoDS_Vertex& aV = *(TopoDS_Vertex*)&myDS->Shape(nVx);
const TopoDS_Edge& aE = *(TopoDS_Edge*) &myDS->Shape(nE);
//
iFlag = myContext->ComputeVE(aV, aE, aT, aTolVNew, myFuzzyValue);
if (iFlag == 0 || iFlag == -4) {
BOPDS_Pave aPave;
//
//
BOPDS_VectorOfInterfVE& aVEs=myDS->InterfVE();
aVEs.SetIncrement(10);
// 1
BOPDS_InterfVE& aVE=aVEs.Appended();
aVE.SetIndices(nV, nE);
aVE.SetParameter(aT);
// 2
myDS->AddInterf(nV, nE);
//
// 3 update vertex V/E if necessary
nVx=UpdateVertex(nV, aTolVNew);
// 4
if (myDS->IsNewShape(nVx)) {
aVE.SetIndexNew(nVx);
}
// 5 append ext pave to pave block
aPave.SetIndex(nVx);
aPave.SetParameter(aT);
aPB->AppendExtPave(aPave);
//
theMEdges.Add(nE);
//
// check for self-interference
Standard_Integer iRV = myDS->Rank(nV);
if (iRV >= 0 && iRV == myDS->Rank(nE)) {
// add warning status
TopoDS_Compound aWC;
BRep_Builder().MakeCompound(aWC);
BRep_Builder().Add(aWC, aV);
BRep_Builder().Add(aWC, aE);
AddWarning (new BOPAlgo_AlertSelfInterferingShape (aWC));
}
return Standard_True;
}
return Standard_False;
}
//=======================================================================
//function : GetPBBox
//purpose :
//=======================================================================
Standard_Boolean BOPAlgo_PaveFiller::GetPBBox(const TopoDS_Edge& theE,
const Handle(BOPDS_PaveBlock)& thePB,
BOPAlgo_DataMapOfPaveBlockBndBox& thePBBox,
Standard_Real& theFirst,
Standard_Real& theLast,
Standard_Real& theSFirst,
Standard_Real& theSLast,
Bnd_Box& theBox)
{
thePB->Range(theFirst, theLast);
// check the validity of PB's range
Standard_Boolean bValid = theLast - theFirst > Precision::PConfusion();
if (!bValid) {
return bValid;
}
//
// check shrunk data
if (thePB->HasShrunkData()) {
Standard_Boolean bIsSplittable;
thePB->ShrunkData(theSFirst, theSLast, theBox, bIsSplittable);
return bValid;
}
//
theSFirst = theFirst;
theSLast = theLast;
// check the map
if (thePBBox.IsBound(thePB)) {
theBox = thePBBox.Find(thePB);
}
else {
// build bounding box
BRepAdaptor_Curve aBAC(theE);
Standard_Real aTol = BRep_Tool::Tolerance(theE) + Precision::Confusion();
BndLib_Add3dCurve::Add(aBAC, theSFirst, theSLast, aTol, theBox);
thePBBox.Bind(thePB, theBox);
}
return bValid;
}
//=======================================================================
//function : UpdateVerticesOfCB
//purpose :
//=======================================================================
void BOPAlgo_PaveFiller::UpdateVerticesOfCB()
{
// Fence map to avoid checking same Common block twice
BOPDS_MapOfPaveBlock aMPBFence;
BOPDS_VectorOfListOfPaveBlock& aPBP = myDS->ChangePaveBlocksPool();
const Standard_Integer aNbPBP = aPBP.Length();
for (Standard_Integer i = 0; i < aNbPBP; ++i)
{
const BOPDS_ListOfPaveBlock& aLPB = aPBP(i);
BOPDS_ListIteratorOfListOfPaveBlock itPB(aLPB);
for (; itPB.More(); itPB.Next())
{
const Handle(BOPDS_CommonBlock)& aCB = myDS->CommonBlock(itPB.Value());
if (aCB.IsNull())
continue;
const Handle(BOPDS_PaveBlock)& aPBR = aCB->PaveBlock1();
if (!aMPBFence.Add(aPBR))
continue;
Standard_Real aTolCB = aCB->Tolerance();
if (aTolCB > 0.)
{
UpdateVertex(aPBR->Pave1().Index(), aTolCB);
UpdateVertex(aPBR->Pave2().Index(), aTolCB);
}
}
}
}
//=======================================================================
//function : ForceInterfEE
//purpose :
//=======================================================================
void BOPAlgo_PaveFiller::ForceInterfEE()
{
// Now that we have vertices increased and unified, try to find additional
// common blocks among the pairs of edges.
// Since all real intersections should have already happened, here we
// are interested in common blocks only, thus we need to check only
// those pairs of pave blocks with the same bounding vertices.
Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator;
// Initialize pave blocks for all vertices which participated in intersections
const Standard_Integer aNbS = myDS->NbSourceShapes();
for (Standard_Integer i = 0; i < aNbS; ++i)
{
const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
if (aSI.ShapeType() == TopAbs_VERTEX)
{
if (myDS->HasInterf(i))
myDS->InitPaveBlocksForVertex(i);
}
}
// Fill the connection map from bounding vertices to pave blocks
// having those bounding vertices
NCollection_IndexedDataMap<BOPDS_Pair,
BOPDS_ListOfPaveBlock,
BOPDS_PairMapHasher> aPBMap(1, anAlloc);
// Fence map of pave blocks
BOPDS_MapOfPaveBlock aMPBFence(1, anAlloc);
for (Standard_Integer i = 0; i < aNbS; ++i)
{
const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
if (aSI.ShapeType() != TopAbs_EDGE)
// Not an edge
continue;
if (!aSI.HasReference())
// Edge has no pave blocks
continue;
if (aSI.HasFlag())
// Degenerated edge
continue;
const BOPDS_ListOfPaveBlock& aLPB = myDS->PaveBlocks(i);
BOPDS_ListIteratorOfListOfPaveBlock aItLPB(aLPB);
for (; aItLPB.More(); aItLPB.Next())
{
const Handle(BOPDS_PaveBlock)& aPB = aItLPB.Value();
const Handle(BOPDS_PaveBlock)& aPBR = myDS->RealPaveBlock(aPB);
if (!aMPBFence.Add(aPBR))
continue;
// Get indices
Standard_Integer nV1, nV2;
aPBR->Indices(nV1, nV2);
// Add pave block to a map
BOPDS_Pair aPair(nV1, nV2);
BOPDS_ListOfPaveBlock *pList = aPBMap.ChangeSeek(aPair);
if (!pList)
pList = &aPBMap(aPBMap.Add(aPair, BOPDS_ListOfPaveBlock(anAlloc)));
pList->Append(aPBR);
}
}
Standard_Integer aNbPB = aPBMap.Extent();
if (!aNbPB)
return;
// Prepare pave blocks with the same vertices for intersection.
BOPAlgo_VectorOfEdgeEdge aVEdgeEdge;
for (Standard_Integer i = 1; i <= aNbPB; ++i)
{
const BOPDS_ListOfPaveBlock& aLPB = aPBMap(i);
if (aLPB.Extent() < 2)
continue;
const BOPDS_Pair& aPair = aPBMap.FindKey(i);
Standard_Integer nV1, nV2;
aPair.Indices(nV1, nV2);
const TopoDS_Vertex& aV1 = TopoDS::Vertex(myDS->Shape(nV1));
const TopoDS_Vertex& aV2 = TopoDS::Vertex(myDS->Shape(nV2));
// Use the max tolerance of vertices as Fuzzy value for intersection
// of edges
Standard_Real aTolAdd = 2 * Max(BRep_Tool::Tolerance(aV1),
BRep_Tool::Tolerance(aV2));
// All possible pairs combined from the list <aLPB> should be checked
BOPDS_ListIteratorOfListOfPaveBlock aItLPB1(aLPB);
for (; aItLPB1.More(); aItLPB1.Next())
{
const Handle(BOPDS_PaveBlock)& aPB1 = aItLPB1.Value();
const Handle(BOPDS_CommonBlock)& aCB1 = myDS->CommonBlock(aPB1);
const Standard_Integer nE1 = aPB1->OriginalEdge();
const Standard_Integer iR1 = myDS->Rank(nE1);
const TopoDS_Edge& aE1 = TopoDS::Edge(myDS->Shape(nE1));
Standard_Real aT11, aT12;
aPB1->Range(aT11, aT12);
BRepAdaptor_Curve aBAC1(aE1);
gp_Pnt aPm;
gp_Vec aVTgt1;
aBAC1.D1((aT11 + aT12) * 0.5, aPm, aVTgt1);
if (aVTgt1.SquareMagnitude() < gp::Resolution())
continue;
BOPDS_ListIteratorOfListOfPaveBlock aItLPB2 = aItLPB1;
for (aItLPB2.Next(); aItLPB2.More(); aItLPB2.Next())
{
const Handle(BOPDS_PaveBlock)& aPB2 = aItLPB2.Value();
const Handle(BOPDS_CommonBlock)& aCB2 = myDS->CommonBlock(aPB2);
const Standard_Integer nE2 = aPB2->OriginalEdge();
const Standard_Integer iR2 = myDS->Rank(nE2);
// Check that the edges came from different arguments
if (iR1 == iR2)
{
// If the sharing of the vertices is not original, but has been acquired
// during the operation, check the coincidence of the edges even if
// they came from the same argument
if ((!myDS->IsNewShape(nV1) && (myDS->Rank(nV1) == iR1)) ||
(!myDS->IsNewShape(nV2) && (myDS->Rank(nV2) == iR2)))
continue;
}
// Check that the Pave blocks do not form the Common block already
if (!aCB1.IsNull() && !aCB2.IsNull())
{
if (aCB1 == aCB2)
continue;
}
const TopoDS_Edge& aE2 = TopoDS::Edge(myDS->Shape(nE2));
Standard_Real aT21, aT22;
aPB2->Range(aT21, aT22);
// Check the angle between edges in the middle point.
// If the angle is more than 10 degrees, do not use the additional
// tolerance, as it may lead to undesired unification of edges
Standard_Boolean bUseAddTol = Standard_True;
{
GeomAPI_ProjectPointOnCurve& aProjPC = myContext->ProjPC(aE2);
aProjPC.Perform(aPm);
if (!aProjPC.NbPoints())
continue;
BRepAdaptor_Curve aBAC2(aE2);
gp_Pnt aPm2;
gp_Vec aVTgt2;
aBAC2.D1(aProjPC.LowerDistanceParameter(), aPm2, aVTgt2);
if (aVTgt2.SquareMagnitude() < gp::Resolution())
continue;
// The angle should be close to zero
Standard_Real aCos = aVTgt1.Dot(aVTgt2);
if (Abs(aCos) < 0.984)
bUseAddTol = Standard_False;
}
// Add pair for intersection
BOPAlgo_EdgeEdge& anEdgeEdge = aVEdgeEdge.Appended();
anEdgeEdge.UseQuickCoincidenceCheck(Standard_True);
anEdgeEdge.SetPaveBlock1(aPB1);
anEdgeEdge.SetPaveBlock2(aPB2);
anEdgeEdge.SetEdge1(aE1, aT11, aT12);
anEdgeEdge.SetEdge2(aE2, aT21, aT22);
if (bUseAddTol)
anEdgeEdge.SetFuzzyValue(myFuzzyValue + aTolAdd);
else
anEdgeEdge.SetFuzzyValue(myFuzzyValue);
anEdgeEdge.SetProgressIndicator(myProgressIndicator);
}
}
}
Standard_Integer aNbPairs = aVEdgeEdge.Length();
if (!aNbPairs)
return;
aPBMap.Clear();
aMPBFence.Clear();
anAlloc->Reset();
// Perform intersection of the found pairs
BOPAlgo_EdgeEdgeCnt::Perform(myRunParallel, aVEdgeEdge);
BOPDS_VectorOfInterfEE& aEEs = myDS->InterfEE();
if (aEEs.IsEmpty())
aEEs.SetIncrement(10);
// Analyze the results of intersection looking for TopAbs_EDGE
// intersection type only.
BOPDS_IndexedDataMapOfPaveBlockListOfPaveBlock aMPBLPB(1, anAlloc);
for (Standard_Integer i = 0; i < aNbPairs; ++i)
{
BOPAlgo_EdgeEdge& anEdgeEdge = aVEdgeEdge(i);
if (!anEdgeEdge.IsDone() || anEdgeEdge.HasErrors())
{
// Warn about failed intersection of sub-shapes
const TopoDS_Shape& aE1 = myDS->Shape(anEdgeEdge.PaveBlock1()->OriginalEdge());
const TopoDS_Shape& aE2 = myDS->Shape(anEdgeEdge.PaveBlock2()->OriginalEdge());
AddIntersectionFailedWarning(aE1, aE2);
continue;
}
const IntTools_SequenceOfCommonPrts& aCParts = anEdgeEdge.CommonParts();
if (aCParts.Length() != 1)
continue;
const IntTools_CommonPrt& aCP = aCParts(1);
if (aCP.Type() != TopAbs_EDGE)
continue;
Handle(BOPDS_PaveBlock) aPB[] = {anEdgeEdge.PaveBlock1(), anEdgeEdge.PaveBlock2()};
const Standard_Integer nE1 = aPB[0]->OriginalEdge();
const Standard_Integer nE2 = aPB[1]->OriginalEdge();
if (myDS->Rank(nE1) == myDS->Rank(nE2))
{
// Add acquired self-interference warning
TopoDS_Compound aWC;
BRep_Builder().MakeCompound(aWC);
BRep_Builder().Add(aWC, myDS->Shape(nE1));
BRep_Builder().Add(aWC, myDS->Shape(nE2));
AddWarning(new BOPAlgo_AlertAcquiredSelfIntersection(aWC));
}
BOPDS_InterfEE& aEE = aEEs.Appended();
aEE.SetIndices(nE1, nE2);
aEE.SetCommonPart(aCP);
myDS->AddInterf(nE1, nE2);
// Fill map for common blocks creation
for (Standard_Integer j = 0; j < 2; ++j)
{
if (myDS->IsCommonBlock(aPB[j]))
{
const BOPDS_ListOfPaveBlock& aLPBCB = myDS->CommonBlock(aPB[j])->PaveBlocks();
BOPDS_ListIteratorOfListOfPaveBlock aItLPB(aLPBCB);
for (; aItLPB.More(); aItLPB.Next())
BOPAlgo_Tools::FillMap<Handle(BOPDS_PaveBlock),
TColStd_MapTransientHasher>(aPB[j], aItLPB.Value(), aMPBLPB, anAlloc);
}
}
BOPAlgo_Tools::FillMap<Handle(BOPDS_PaveBlock),
TColStd_MapTransientHasher>(aPB[0], aPB[1], aMPBLPB, anAlloc);
}
// Create new common blocks of coinciding pairs.
BOPAlgo_Tools::PerformCommonBlocks(aMPBLPB, anAlloc, myDS);
}