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_Builder_2.cxx
dpasukhi 1103eb60af 0033370: Foundation Classes - Moving into STL and Boost functionality
NCollection containers update:
  - NCollection_Array1 - updated functionality
  - NCollection_Array2 - NCollection_Array1 as a wrapper for 2array
  - NCollection_Vector -> NCollection_DynamicArray was renamed and reworked.
TCollection:
  - Use static empty string to avoid allocations on empty string
 NCollection allocators update:
  - NCollection_Allocator - allocator that used Standard::Allocate
  - NCollection_OccAllocator - allocator-wrapper that used OCC BaseAllocator objects
  - NCollection_IncAllocator - rework to increase performance
Standard:
  - Rework functionality to use different allocation libs
  - Implement basic of new way to wrap allocations tools
  - Define 4 ways to allocation (defines in configure stage)
 Additional changes:
  - Hash function uses std::hash functionality
   - size_t as a hash value
  - New HashUtils with Murmur and FVN hash algo for x32 and x64
  - Deprecated _0.cxx and .gxx DE classes reorganized
  - Create own utility for std memory
  - Update Standard_Transient to be more platform-independent
 Math TK changes:
  - math_Vector -> match_BaseVector<>
    - Buffer decreased to cash 32 elements instead of 512
2023-12-04 13:37:09 +00:00

1066 lines
32 KiB
C++

// Created by: Peter KURNEV
// Copyright (c) 2010-2014 OPEN CASCADE SAS
// Copyright (c) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
// Copyright (c) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, CEDRAT,
// EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <BOPAlgo_Builder.hxx>
#include <BOPAlgo_Alerts.hxx>
#include <BOPAlgo_BuilderFace.hxx>
#include <BOPAlgo_PaveFiller.hxx>
#include <BOPAlgo_Tools.hxx>
#include <BOPDS_DS.hxx>
#include <BOPDS_FaceInfo.hxx>
#include <BOPDS_Interf.hxx>
#include <BOPDS_PaveBlock.hxx>
#include <BOPDS_ShapeInfo.hxx>
#include <BOPDS_VectorOfInterfFF.hxx>
#include <BOPTools_AlgoTools.hxx>
#include <BOPTools_AlgoTools2D.hxx>
#include <BOPTools_AlgoTools3D.hxx>
#include <BOPTools_MapOfSet.hxx>
#include <BOPTools_Parallel.hxx>
#include <BRep_Builder.hxx>
#include <BRepLib.hxx>
#include <BRep_Tool.hxx>
#include <GeomLib.hxx>
#include <NCollection_IncAllocator.hxx>
#include <NCollection_Vector.hxx>
#include <IntTools_Context.hxx>
#include <TColStd_ListOfInteger.hxx>
#include <TColStd_MapOfInteger.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopTools_ListOfShape.hxx>
#include <algorithm>
//
static
TopoDS_Face BuildDraftFace(const TopoDS_Face& theFace,
const TopTools_DataMapOfShapeListOfShape& theImages,
Handle(IntTools_Context)& theCtx,
const Handle(Message_Report)& theReport);
//=======================================================================
//class : BOPAlgo_PairOfShapeBoolean
//purpose :
//=======================================================================
class BOPAlgo_PairOfShapeBoolean : public BOPAlgo_ParallelAlgo {
public:
DEFINE_STANDARD_ALLOC
BOPAlgo_PairOfShapeBoolean() :
BOPAlgo_ParallelAlgo(),
myFlag(Standard_False) {
}
//
virtual ~BOPAlgo_PairOfShapeBoolean() {
}
//
TopoDS_Shape& Shape1() {
return myShape1;
}
//
TopoDS_Shape& Shape2() {
return myShape2;
}
//
Standard_Boolean& Flag() {
return myFlag;
}
//
void SetContext(const Handle(IntTools_Context)& aContext) {
myContext=aContext;
}
//
const Handle(IntTools_Context)& Context()const {
return myContext;
}
//
virtual void Perform() {
Message_ProgressScope aPS(myProgressRange, NULL, 1);
if (UserBreak(aPS))
{
return;
}
const TopoDS_Face& aFj=*((TopoDS_Face*)&myShape1);
const TopoDS_Face& aFk=*((TopoDS_Face*)&myShape2);
myFlag=BOPTools_AlgoTools::AreFacesSameDomain(aFj, aFk, myContext, myFuzzyValue);
}
//
protected:
Standard_Boolean myFlag;
TopoDS_Shape myShape1;
TopoDS_Shape myShape2;
Handle(IntTools_Context) myContext;
};
//
typedef NCollection_Vector<BOPAlgo_PairOfShapeBoolean> BOPAlgo_VectorOfPairOfShapeBoolean;
//=======================================================================
//class : BOPAlgo_SplitFace
//purpose : Auxiliary class to extend BOPAlgo_BuilderFace with progress support
//=======================================================================
class BOPAlgo_SplitFace : public BOPAlgo_BuilderFace
{
public:
//! Sets progress range
void SetProgressRange(const Message_ProgressRange& theRange)
{
myRange = theRange;
}
// New perform method, using own progress range
void Perform()
{
Message_ProgressScope aPS(myRange, NULL, 1);
if (!aPS.More())
{
return;
}
BOPAlgo_BuilderFace::Perform(aPS.Next());
}
private:
//! Disable the range enabled method
virtual void Perform(const Message_ProgressRange& /*theRange*/) {};
private:
Message_ProgressRange myRange;
};
typedef NCollection_Vector<BOPAlgo_SplitFace> BOPAlgo_VectorOfBuilderFace;
//=======================================================================
//class : BOPAlgo_VFI
//purpose :
//=======================================================================
class BOPAlgo_VFI : public BOPAlgo_ParallelAlgo {
public:
DEFINE_STANDARD_ALLOC
BOPAlgo_VFI() :
BOPAlgo_ParallelAlgo(),
myIsInternal(Standard_False) {
}
//
virtual ~BOPAlgo_VFI(){
}
//
void SetVertex(const TopoDS_Vertex& aV) {
myV=aV;
}
//
TopoDS_Vertex& Vertex() {
return myV;
}
//
void SetFace(const TopoDS_Face& aF) {
myF=aF;
}
//
TopoDS_Face& Face() {
return myF;
}
//
Standard_Boolean IsInternal()const {
return myIsInternal;
}
//
void SetContext(const Handle(IntTools_Context)& aContext) {
myContext=aContext;
}
//
const Handle(IntTools_Context)& Context()const {
return myContext;
}
//
virtual void Perform() {
Message_ProgressScope aPS(myProgressRange, NULL, 1);
if (UserBreak(aPS))
{
return;
}
Standard_Real aT1, aT2, dummy;
//
Standard_Integer iFlag =
myContext->ComputeVF(myV, myF, aT1, aT2, dummy, myFuzzyValue);
myIsInternal = (iFlag == 0);
}
//
protected:
Standard_Boolean myIsInternal;
TopoDS_Vertex myV;
TopoDS_Face myF;
Handle(IntTools_Context) myContext;
};
//
typedef NCollection_Vector<BOPAlgo_VFI> BOPAlgo_VectorOfVFI;
//=======================================================================
//function : FillImagesFaces
//purpose :
//=======================================================================
void BOPAlgo_Builder::FillImagesFaces(const Message_ProgressRange& theRange)
{
Message_ProgressScope aPS(theRange, "Filing spligs of faces", 10);
BuildSplitFaces(aPS.Next(9));
if (HasErrors())
{
return;
}
FillSameDomainFaces(aPS.Next(0.5));
if (HasErrors())
{
return;
}
FillInternalVertices(aPS.Next(0.5));
}
//=======================================================================
//function : BuildSplitFaces
//purpose :
//=======================================================================
void BOPAlgo_Builder::BuildSplitFaces(const Message_ProgressRange& theRange)
{
Standard_Boolean bHasFaceInfo, bIsClosed, bIsDegenerated, bToReverse;
Standard_Integer i, j, k, aNbS, aNbPBIn, aNbPBOn, aNbPBSc, aNbAV, nSp;
TopoDS_Face aFF, aFSD;
TopoDS_Edge aSp, aEE;
TopAbs_Orientation anOriF, anOriE;
TopExp_Explorer aExp;
TopTools_ListIteratorOfListOfShape aIt;
TColStd_ListOfInteger aLIAV;
TopTools_MapOfShape aMFence;
Handle(NCollection_BaseAllocator) aAllocator;
BOPAlgo_VectorOfBuilderFace aVBF;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~scope f
aAllocator=
NCollection_BaseAllocator::CommonBaseAllocator();
//
TopTools_ListOfShape aLE(aAllocator);
TopTools_MapOfShape aMDE(100, aAllocator);
//
Message_ProgressScope aPSOuter(theRange, NULL, 10);
// Build temporary map of faces images to avoid rebuilding
// of the faces without any IN or section edges
NCollection_IndexedDataMap<Standard_Integer, TopTools_ListOfShape> aFacesIm;
//
aNbS=myDS->NbSourceShapes();
//
for (i=0; i<aNbS; ++i) {
const BOPDS_ShapeInfo& aSI=myDS->ShapeInfo(i);
if (aSI.ShapeType()!=TopAbs_FACE) {
continue;
}
if (UserBreak(aPSOuter))
{
return;
}
//
const TopoDS_Face& aF=(*(TopoDS_Face*)(&aSI.Shape()));
Standard_Boolean isUClosed = Standard_False,
isVClosed = Standard_False,
isChecked = Standard_False;
//
bHasFaceInfo=myDS->HasFaceInfo(i);
if(!bHasFaceInfo) {
continue;
}
//
const BOPDS_FaceInfo& aFI=myDS->FaceInfo(i);
//
const BOPDS_IndexedMapOfPaveBlock& aMPBIn=aFI.PaveBlocksIn();
const BOPDS_IndexedMapOfPaveBlock& aMPBOn=aFI.PaveBlocksOn();
const BOPDS_IndexedMapOfPaveBlock& aMPBSc=aFI.PaveBlocksSc();
aLIAV.Clear();
myDS->AloneVertices(i, aLIAV);
aNbPBIn=aMPBIn.Extent();
aNbPBOn=aMPBOn.Extent();
aNbPBSc=aMPBSc.Extent();
aNbAV=aLIAV.Extent();
if (!aNbPBIn && !aNbPBOn && !aNbPBSc && !aNbAV) { // not compete
continue;
}
if (!aNbPBIn && !aNbPBSc)
{
// If there are any alone vertices to be put in the face,
// the new face has to be created even if the wires of the
// face have not been modified.
// It is also necessary to check if the face contains any internal edges,
// as such edges may split the face on parts and it is better
// to send the face be treated by the BuilderFace algorithm.
// In case of alone vertices the check for internals will be performed
// in the BuildDraftFace method.
Standard_Boolean hasInternals = Standard_False;
if (!aNbAV)
{
// Check if any wires of the face have been modified.
// If no modified and internal wires present in the face
// there is no need to create the new face.
Standard_Boolean hasModified = Standard_False;
TopoDS_Iterator aItW(aF);
for (; aItW.More(); aItW.Next())
{
TopoDS_Iterator itE(aItW.Value());
hasInternals = (itE.More() && (itE.Value().Orientation() == TopAbs_INTERNAL));
if (hasInternals)
break;
hasModified |= myImages.IsBound(aItW.Value());
}
if (!hasInternals && !hasModified)
continue;
}
if (!hasInternals)
{
// No internal parts for the face, so just build the draft face
// and keep it to pass directly into result.
// If the original face has any internal edges or multi-connected vertices,
// the draft face will be null, as such sub-shapes may split the face on parts
// (as in the case "bugs modalg_5 bug25245_1").
// The BuilderFace algorithm will be called in this case.
TopoDS_Face aFD = BuildDraftFace(aF, myImages, myContext, myReport);
if (!aFD.IsNull())
{
aFacesIm(aFacesIm.Add(i, TopTools_ListOfShape())).Append(aFD);
continue;
}
}
}
aMFence.Clear();
//
anOriF=aF.Orientation();
aFF=aF;
aFF.Orientation(TopAbs_FORWARD);
//
// 1. Fill the edges set for the face aFF -> LE
aLE.Clear();
// 1.1 Bounding edges
aExp.Init(aFF, TopAbs_EDGE);
for (; aExp.More(); aExp.Next()) {
const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&aExp.Current()));
anOriE=aE.Orientation();
//
if (!myImages.IsBound(aE)) {
if (anOriE==TopAbs_INTERNAL) {
aEE=aE;
aEE.Orientation(TopAbs_FORWARD);
aLE.Append(aEE);
aEE.Orientation(TopAbs_REVERSED);
aLE.Append(aEE);
}
else {
aLE.Append(aE);
}
continue;
}
if(!isChecked)
{
const Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aF);
GeomLib::IsClosed(aSurf, BRep_Tool::Tolerance(aE),
isUClosed, isVClosed);
isChecked = Standard_True;
}
bIsClosed = Standard_False;
if((isUClosed || isVClosed) && BRep_Tool::IsClosed(aE, aF))
{
Standard_Boolean isUIso = Standard_False, isVIso = Standard_False;
BOPTools_AlgoTools2D::IsEdgeIsoline(aE, aF, isUIso, isVIso);
bIsClosed = ((isUClosed && isUIso) || (isVClosed && isVIso));
}
bIsDegenerated=BRep_Tool::Degenerated(aE);
const TopTools_ListOfShape& aLIE=myImages.Find(aE);
aIt.Initialize(aLIE);
for (; aIt.More(); aIt.Next()) {
aSp=(*(TopoDS_Edge*)(&aIt.Value()));
if (bIsDegenerated) {
aSp.Orientation(anOriE);
aLE.Append(aSp);
continue;
}
//
if (anOriE==TopAbs_INTERNAL) {
aSp.Orientation(TopAbs_FORWARD);
aLE.Append(aSp);
aSp.Orientation(TopAbs_REVERSED);
aLE.Append(aSp);
continue;
}
//
if (bIsClosed) {
if (aMFence.Add(aSp)) {
if (!BRep_Tool::IsClosed(aSp, aF)){
if (!BOPTools_AlgoTools3D::DoSplitSEAMOnFace(aSp, aF))
{
// try different approach
if (!BOPTools_AlgoTools3D::DoSplitSEAMOnFace(aE, aSp, aF))
{
TopoDS_Compound aWS;
BRep_Builder().MakeCompound (aWS);
BRep_Builder().Add (aWS, aF);
BRep_Builder().Add (aWS, aSp);
AddWarning (new BOPAlgo_AlertUnableToMakeClosedEdgeOnFace (aWS));
}
}
}
//
aSp.Orientation(TopAbs_FORWARD);
aLE.Append(aSp);
aSp.Orientation(TopAbs_REVERSED);
aLE.Append(aSp);
}// if (aMFence.Add(aSp))
continue;
}// if (bIsClosed){
//
aSp.Orientation(anOriE);
bToReverse=BOPTools_AlgoTools::IsSplitToReverseWithWarn(aSp, aE, myContext, myReport);
if (bToReverse) {
aSp.Reverse();
}
aLE.Append(aSp);
}// for (; aIt.More(); aIt.Next()) {
}// for (; aExp.More(); aExp.Next()) {
//
//
// 1.2 In edges
for (j=1; j<=aNbPBIn; ++j) {
const Handle(BOPDS_PaveBlock)& aPB=aMPBIn(j);
nSp=aPB->Edge();
Standard_ASSERT(nSp >= 0, "Face information is not up to date", continue);
aSp=(*(TopoDS_Edge*)(&myDS->Shape(nSp)));
//
aSp.Orientation(TopAbs_FORWARD);
aLE.Append(aSp);
aSp.Orientation(TopAbs_REVERSED);
aLE.Append(aSp);
}
//
//
// 1.3 Section edges
for (j=1; j<=aNbPBSc; ++j) {
const Handle(BOPDS_PaveBlock)& aPB=aMPBSc(j);
nSp=aPB->Edge();
aSp=(*(TopoDS_Edge*)(&myDS->Shape(nSp)));
//
aSp.Orientation(TopAbs_FORWARD);
aLE.Append(aSp);
aSp.Orientation(TopAbs_REVERSED);
aLE.Append(aSp);
}
//
if (!myPaveFiller->NonDestructive()) {
// speed up for planar faces
BRepLib::BuildPCurveForEdgesOnPlane(aLE, aFF);
}
// 3 Build split faces
BOPAlgo_SplitFace& aBF=aVBF.Appended();
aBF.SetFace(aF);
aBF.SetShapes(aLE);
aBF.SetRunParallel(myRunParallel);
//
}// for (i=0; i<aNbS; ++i) {
// close preparation task
aPSOuter.Next();
//
Standard_Integer aNbBF = aVBF.Length();
// Set progress range for each task to be run in parallel
Message_ProgressScope aPSParallel(aPSOuter.Next(9), "Splitting faces", aNbBF);
for (Standard_Integer iF = 0; iF < aNbBF; iF++)
{
BOPAlgo_SplitFace& aBF = aVBF.ChangeValue(iF);
aBF.SetProgressRange(aPSParallel.Next());
}
//===================================================
BOPTools_Parallel::Perform (myRunParallel, aVBF);
//===================================================
if (UserBreak(aPSOuter))
{
return;
}
for (k = 0; k < aNbBF; ++k)
{
BOPAlgo_BuilderFace& aBF = aVBF(k);
aFacesIm.Add(myDS->Index(aBF.Face()), aBF.Areas());
myReport->Merge(aBF.GetReport());
}
aNbBF = aFacesIm.Extent();
for (k = 1; k <= aNbBF; ++k)
{
const TopoDS_Face& aF = TopoDS::Face(myDS->Shape(aFacesIm.FindKey(k)));
anOriF = aF.Orientation();
const TopTools_ListOfShape& aLFR = aFacesIm(k);
//
TopTools_ListOfShape* pLFIm = myImages.Bound(aF, TopTools_ListOfShape());
aIt.Initialize(aLFR);
for (; aIt.More(); aIt.Next()) {
TopoDS_Shape& aFR=aIt.ChangeValue();
if (anOriF==TopAbs_REVERSED)
aFR.Orientation(TopAbs_REVERSED);
pLFIm->Append(aFR);
}
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~scope t
}
//=======================================================================
//function : AddEdgeSet
//purpose :
//=======================================================================
typedef
NCollection_IndexedDataMap<BOPTools_Set,
TopTools_ListOfShape> BOPAlgo_IndexedDataMapOfSetListOfShape;
static void AddEdgeSet(const TopoDS_Shape& theS,
BOPAlgo_IndexedDataMapOfSetListOfShape& theMap,
const Handle(NCollection_BaseAllocator)& theAllocator)
{
// Make set
BOPTools_Set aSE;
aSE.Add(theS, TopAbs_EDGE);
// Add set to the map, keeping connection to the shape
TopTools_ListOfShape* pLF = theMap.ChangeSeek(aSE);
if (!pLF)
pLF = &theMap(theMap.Add(aSE, TopTools_ListOfShape(theAllocator)));
pLF->Append(theS);
}
//=======================================================================
//function : FillSameDomainFaces
//purpose :
//=======================================================================
void BOPAlgo_Builder::FillSameDomainFaces(const Message_ProgressRange& theRange)
{
// It is necessary to analyze all Face/Face intersections
// and find all faces with equal sets of edges
const BOPDS_VectorOfInterfFF& aFFs = myDS->InterfFF();
Standard_Integer aNbFFs = aFFs.Length();
if (!aNbFFs)
return;
Message_ProgressScope aPSOuter(theRange, NULL, 10);
Handle(NCollection_BaseAllocator) aAllocator = new NCollection_IncAllocator;
// Vector to store the indices of faces for future sorting
// for making the SD face for the group from the face with
// smallest index in Data structure
NCollection_Vector<Standard_Integer> aFIVec(256, aAllocator);
// Fence map to avoid repeated checks of the same face.
TColStd_MapOfInteger aMFence(1, aAllocator);
// Fill the vector with indices of faces
for (Standard_Integer i = 0; i < aNbFFs; ++i)
{
if (UserBreak(aPSOuter))
{
return;
}
const BOPDS_InterfFF& aFF = aFFs(i);
// get indices
Standard_Integer nF[2];
aFF.Indices(nF[0], nF[1]);
// store indices to the vector
for (Standard_Integer j = 0; j < 2; ++j)
{
if (!myDS->HasFaceInfo(nF[j]))
continue;
if (!aMFence.Add(nF[j]))
continue;
aFIVec.Appended() = nF[j];
}
}
// Sort the indices
std::sort(aFIVec.begin(), aFIVec.end());
// Data map of set of edges with all faces having this set
NCollection_IndexedDataMap<BOPTools_Set,
TopTools_ListOfShape> anESetFaces(1, aAllocator);
// Map of planar bounded faces. If such faces have the same Edge set
// they are considered Same domain, without additional check.
TopTools_MapOfShape aMFPlanar(1, aAllocator);
Standard_Integer aNbF = aFIVec.Length();
for (Standard_Integer i = 0; i < aNbF; ++i)
{
if (UserBreak(aPSOuter))
{
return;
}
const Standard_Integer nF = aFIVec(i);
const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(nF);
const TopoDS_Shape& aF = aSI.Shape();
Standard_Boolean bCheckPlanar = Standard_False;
{
// At this stage, context should contain adaptor for all intersected faces,
// so getting a type of the underlying surface should be done at no cost.
if (myContext->SurfaceAdaptor(TopoDS::Face(aF)).GetType() == GeomAbs_Plane)
{
// Check bounding box of the face - it should not be open in any side
const Bnd_Box& aBox = aSI.Box();
bCheckPlanar = !(aBox.IsOpenXmin() || aBox.IsOpenXmax() ||
aBox.IsOpenYmin() || aBox.IsOpenYmax() ||
aBox.IsOpenZmin() || aBox.IsOpenZmax());
}
}
const TopTools_ListOfShape* pLFSp = myImages.Seek(aF);
if (pLFSp)
{
TopTools_ListIteratorOfListOfShape aItLF(*pLFSp);
for (; aItLF.More(); aItLF.Next())
{
AddEdgeSet(aItLF.Value(), anESetFaces, aAllocator);
if (bCheckPlanar)
aMFPlanar.Add(aItLF.Value());
}
}
else
{
AddEdgeSet(aF, anESetFaces, aAllocator);
if (bCheckPlanar)
aMFPlanar.Add(aF);
}
}
// Store pairs of faces with equal set of edges to check if they are really Same Domain
BOPAlgo_VectorOfPairOfShapeBoolean aVPSB;
// Back and forth map of SD faces to make the blocks
TopTools_IndexedDataMapOfShapeListOfShape aDMSLS(1, aAllocator);
Standard_Integer aNbSets = anESetFaces.Extent();
for (Standard_Integer i = 1; i <= aNbSets; ++i)
{
if (UserBreak(aPSOuter))
{
return;
}
const TopTools_ListOfShape& aLF = anESetFaces(i);
if (aLF.Extent() < 2)
continue;
// All possible pairs from <aLF> should be checked
TopTools_ListIteratorOfListOfShape aIt1(aLF);
for (; aIt1.More(); aIt1.Next())
{
const TopoDS_Shape& aF1 = aIt1.Value();
Standard_Boolean bCheckPlanar = aMFPlanar.Contains(aF1);
TopTools_ListIteratorOfListOfShape aIt2 = aIt1;
for (aIt2.Next(); aIt2.More(); aIt2.Next())
{
const TopoDS_Shape& aF2 = aIt2.Value();
if (bCheckPlanar && aMFPlanar.Contains(aF2))
{
// Consider planar bounded faces as Same Domain without additional check
BOPAlgo_Tools::FillMap(aF1, aF2, aDMSLS, aAllocator);
continue;
}
// Add pair for analysis
BOPAlgo_PairOfShapeBoolean& aPSB = aVPSB.Appended();
aPSB.Shape1() = aF1;
aPSB.Shape2() = aF2;
aPSB.SetFuzzyValue(myFuzzyValue);
}
}
}
aPSOuter.Next();
// Set progress range for each task to be run in parallel
Message_ProgressScope aPSParallel(aPSOuter.Next(6), "Checking SD faces", aVPSB.Size());
for (Standard_Integer iPSB = 0; iPSB < aVPSB.Size(); ++iPSB)
{
aVPSB.ChangeValue(iPSB).SetProgressRange(aPSParallel.Next());
}
//================================================================
// Perform analysis
BOPTools_Parallel::Perform (myRunParallel, aVPSB, myContext);
//================================================================
if (UserBreak(aPSOuter))
{
return;
}
NCollection_List<TopTools_ListOfShape> aMBlocks(aAllocator);
// Fill map with SD faces to make the blocks
Standard_Integer aNbPairs = aVPSB.Length();
for (Standard_Integer i = 0; i < aNbPairs; ++i)
{
BOPAlgo_PairOfShapeBoolean& aPSB = aVPSB(i);
if (aPSB.Flag())
BOPAlgo_Tools::FillMap(aPSB.Shape1(), aPSB.Shape2(), aDMSLS, aAllocator);
}
aVPSB.Clear();
// Make blocks of SD faces using the back and forth map
BOPAlgo_Tools::MakeBlocks(aDMSLS, aMBlocks, aAllocator);
Message_ProgressScope aPS(aPSOuter.Next(3), "Filling same domain faces map", aMBlocks.Size());
// Fill same domain faces map
NCollection_List<TopTools_ListOfShape>::Iterator aItB(aMBlocks);
for (; aItB.More(); aItB.Next(), aPS.Next())
{
if (UserBreak(aPS))
{
return;
}
const TopTools_ListOfShape& aLSD = aItB.Value();
// If the group contains some original faces, the one with minimal
// index in the DS will be chosen as the SD for the whole group.
// If there are no original faces in the group, the first face from
// the group will be used as the SD face.
// Such SD face will be representative of the whole group in the result.
TopoDS_Face* pFSD = NULL;
Standard_Integer nFMin = ::IntegerLast();
TopTools_ListIteratorOfListOfShape aItLF(aLSD);
for (; aItLF.More(); aItLF.Next())
{
const TopoDS_Shape& aF = aItLF.Value();
// Check the index of the face in DS
const Standard_Integer nF = myDS->Index(aF);
if (nF >= 0)
{
// The fact that the face is found in the DS, means that
// the face has not been change, and thus it is original one.
//
// Such face does not have any splits, but have an SD face.
// Consider it being split.
myImages.Bound(aF, TopTools_ListOfShape())->Append(aF);
// For the SD face chose the one with minimal index
if (nF < nFMin)
{
nFMin = nF;
pFSD = (TopoDS_Face*)&aF;
}
}
}
if (!pFSD)
{
// No original faces in the group, take the first one
pFSD = (TopoDS_Face*)&aLSD.First();
}
// Save all SD connections
aItLF.Initialize(aLSD);
for (; aItLF.More(); aItLF.Next())
{
const TopoDS_Shape& aF = aItLF.Value();
myShapesSD.Bind(aF, *pFSD);
}
}
// Update the map of images with SD faces and
// fill the map of origins.
Standard_Integer aNbS = myDS->NbSourceShapes();
for (Standard_Integer i = 0; i < aNbS; ++i)
{
const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
if (aSI.ShapeType() != TopAbs_FACE)
continue;
const TopoDS_Shape& aF = aSI.Shape();
TopTools_ListOfShape* pLFIm = myImages.ChangeSeek(aF);
if (!pLFIm)
continue;
TopTools_ListIteratorOfListOfShape aItLFIm(*pLFIm);
for (; aItLFIm.More(); aItLFIm.Next())
{
TopoDS_Shape& aFIm = aItLFIm.ChangeValue();
const TopoDS_Shape* pFSD = myShapesSD.Seek(aFIm);
if (pFSD)
// Update image with SD face
aFIm = *pFSD;
// Fill the map of origins
TopTools_ListOfShape* pLFOr = myOrigins.ChangeSeek(aFIm);
if (!pLFOr)
pLFOr = myOrigins.Bound(aFIm, TopTools_ListOfShape());
pLFOr->Append(aF);
}
}
aMBlocks.Clear();
aDMSLS.Clear();
}
//=======================================================================
// function: FillImagesFaces1
// purpose:
//=======================================================================
void BOPAlgo_Builder::FillInternalVertices(const Message_ProgressRange& theRange)
{
Message_ProgressScope aPSOuter(theRange, NULL, 1);
// Vector of pairs of Vertex/Face for classification of the vertices
// relatively faces, and adding them as internal into the faces
BOPAlgo_VectorOfVFI aVVFI;
Standard_Integer aNbS = myDS->NbSourceShapes();
for (Standard_Integer i = 0; i < aNbS; ++i)
{
const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
if (aSI.ShapeType() != TopAbs_FACE)
continue;
if (UserBreak(aPSOuter))
{
return;
}
const TopoDS_Shape& aF = aSI.Shape();
const TopTools_ListOfShape* pLFIm = myImages.Seek(aF);
if (!pLFIm)
continue;
// Find vertices to add as internal into the splits
TColStd_ListOfInteger aLIAV;
myDS->AloneVertices(i, aLIAV);
// Add vertices and faces for classification
TColStd_ListIteratorOfListOfInteger aItLV(aLIAV);
for (; aItLV.More(); aItLV.Next())
{
TopoDS_Vertex aV = TopoDS::Vertex(myDS->Shape(aItLV.Value()));
aV.Orientation(TopAbs_INTERNAL);
TopTools_ListIteratorOfListOfShape aItLFIm(*pLFIm);
for (; aItLFIm.More(); aItLFIm.Next())
{
const TopoDS_Face& aFIm = TopoDS::Face(aItLFIm.Value());
// Make the pair
BOPAlgo_VFI& aVFI = aVVFI.Appended();
aVFI.SetVertex(aV);
aVFI.SetFace(aFIm);
aVFI.SetFuzzyValue(myFuzzyValue);
}
}
}
// Set progress range for each task to be run in parallel
Message_ProgressScope aPSParallel(aPSOuter.Next(), "Looking for internal shapes", aVVFI.Size());
for (Standard_Integer iVFI = 0; iVFI< aVVFI.Size(); ++iVFI)
{
aVVFI.ChangeValue(iVFI).SetProgressRange(aPSParallel.Next());
}
// Perform classification
//================================================================
BOPTools_Parallel::Perform (myRunParallel, aVVFI, myContext);
//================================================================
if (UserBreak(aPSOuter))
{
return;
}
Standard_Integer aNbVFI = aVVFI.Length();
for (Standard_Integer i = 0; i < aNbVFI; ++i)
{
BOPAlgo_VFI& aVFI = aVVFI(i);
if (aVFI.IsInternal())
{
TopoDS_Vertex& aV = aVFI.Vertex();
TopoDS_Face& aF = aVFI.Face();
BRep_Builder().Add(aF, aV);
}
}
}
//=======================================================================
//function : HasMultiConnected
//purpose : Checks if the edge has multi-connected vertices.
//=======================================================================
static Standard_Boolean HasMultiConnected(const TopoDS_Edge& theEdge,
TopTools_DataMapOfShapeListOfShape& theMap)
{
TopoDS_Iterator itV(theEdge);
for (; itV.More(); itV.Next())
{
const TopoDS_Shape& aV = itV.Value();
TopTools_ListOfShape *pList = theMap.ChangeSeek(aV);
if (!pList)
{
pList = theMap.Bound(aV, TopTools_ListOfShape());
pList->Append(theEdge);
}
else
{
// The list is expected to be 1-2 elements long,
// thus using "Contains" is safe.
if (!pList->Contains(theEdge))
pList->Append(theEdge);
if (pList->Extent() > 2)
return Standard_True;
}
}
return Standard_False;
}
//=======================================================================
//function : BuildDraftFace
//purpose : Build draft faces, updating the bounding edges,
// according to the information stored into the <theImages> map
//=======================================================================
TopoDS_Face BuildDraftFace(const TopoDS_Face& theFace,
const TopTools_DataMapOfShapeListOfShape& theImages,
Handle(IntTools_Context)& theCtx,
const Handle(Message_Report)& theReport)
{
BRep_Builder aBB;
// Take the information from the original face
TopLoc_Location aLoc;
const Handle(Geom_Surface)& aS = BRep_Tool::Surface(theFace, aLoc);
const Standard_Real aTol = BRep_Tool::Tolerance(theFace);
// Make the new face, without any wires
TopoDS_Face aDraftFace;
aBB.MakeFace(aDraftFace, aS, aLoc, aTol);
// Check if the thin face can be split by a vertex - in this case
// this vertex will be contained in more than two edges. Thus, count
// the vertices appearance, and if the multi-connexity is met return
// the null face to use the BuilderFace algorithm for checking the
// possibility of split.
TopTools_DataMapOfShapeListOfShape aVerticesCounter;
// Check that the edges of the initial face have not been unified during intersection.
// Otherwise, it will be necessary to check validity of the new wires.
TopTools_MapOfShape aMEdges;
// Update wires of the original face and add them to draft face
TopoDS_Iterator aItW(theFace.Oriented(TopAbs_FORWARD));
for (; aItW.More(); aItW.Next())
{
const TopoDS_Shape& aW = aItW.Value();
if (aW.ShapeType() != TopAbs_WIRE)
continue;
// Rebuild wire using images of edges
TopoDS_Iterator aItE(aW.Oriented(TopAbs_FORWARD));
if (!aItE.More())
continue;
TopoDS_Wire aNewWire;
aBB.MakeWire(aNewWire);
for (; aItE.More(); aItE.Next())
{
const TopoDS_Edge& aE = TopoDS::Edge(aItE.Value());
TopAbs_Orientation anOriE = aE.Orientation();
if (anOriE == TopAbs_INTERNAL)
{
// The internal edges could split the original face on halves.
// Thus, use the BuilderFace algorithm to build the new face.
return TopoDS_Face();
}
// Check if the original edge is degenerated
Standard_Boolean bIsDegenerated = BRep_Tool::Degenerated(aE);
// Check if the original edge is closed on the face
Standard_Boolean bIsClosed = BRep_Tool::IsClosed(aE, theFace);
// Check for the splits of the edge
const TopTools_ListOfShape* pLEIm = theImages.Seek(aE);
if (!pLEIm)
{
// Check if the edge has multi-connected vertices
if (!bIsDegenerated && HasMultiConnected(aE, aVerticesCounter))
return TopoDS_Face();
// Check edges unification
if (!bIsClosed && !aMEdges.Add(aE))
return TopoDS_Face();
aBB.Add(aNewWire, aE);
continue;
}
TopTools_ListIteratorOfListOfShape aItLEIm(*pLEIm);
for (; aItLEIm.More(); aItLEIm.Next())
{
TopoDS_Edge& aSp = TopoDS::Edge(aItLEIm.ChangeValue());
// Check if the split has multi-connected vertices
if (!bIsDegenerated && HasMultiConnected(aSp, aVerticesCounter))
return TopoDS_Face();
// Check edges unification
if (!bIsClosed && !aMEdges.Add(aSp))
return TopoDS_Face();
aSp.Orientation(anOriE);
if (bIsDegenerated)
{
aBB.Add(aNewWire, aSp);
continue;
}
// If the original edge is closed on the face check closeness
// of the split edge and if it is not closed make the second PCurve
if (bIsClosed && !BRep_Tool::IsClosed(aSp, theFace))
BOPTools_AlgoTools3D::DoSplitSEAMOnFace(aSp, theFace);
// Check if the split should be reversed
if (BOPTools_AlgoTools::IsSplitToReverseWithWarn(aSp, aE, theCtx, theReport))
aSp.Reverse();
aBB.Add(aNewWire, aSp);
}
}
aNewWire.Orientation(aW.Orientation());
aNewWire.Closed(BRep_Tool::IsClosed(aNewWire));
aBB.Add(aDraftFace, aNewWire);
}
if (theFace.Orientation() == TopAbs_REVERSED)
aDraftFace.Reverse();
return aDraftFace;
}