mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-08-10 08:19:37 +08:00
6c24544fe1
- Refactor boolean expressions and improve code readability across multiple files - Simplified boolean expressions by removing unnecessary comparisons to true/false. - Replaced explicit boolean checks with direct variable usage Used flags: readability-static-accessed-through-instance readability-simplify-boolean-expr performance-for-range-copy performance-move-const-arg misc-unused-parameters misc-redundant-expression
2357 lines
69 KiB
C++
2357 lines
69 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 <BOPTools_AlgoTools.hxx>
|
|
#include <BOPAlgo_Alerts.hxx>
|
|
#include <BOPTools_AlgoTools2D.hxx>
|
|
#include <BOPTools_AlgoTools3D.hxx>
|
|
#include <BOPTools_CoupleOfShape.hxx>
|
|
#include <NCollection_List.hxx>
|
|
#include <BRep_Builder.hxx>
|
|
#include <BRep_Tool.hxx>
|
|
#include <BRepAdaptor_Curve2d.hxx>
|
|
#include <BRepClass3d_SolidClassifier.hxx>
|
|
#include <BRepLib.hxx>
|
|
#include <Geom2d_Curve.hxx>
|
|
#include <Geom2dInt_Geom2dCurveTool.hxx>
|
|
#include <Geom_Curve.hxx>
|
|
#include <Geom_Plane.hxx>
|
|
#include <Geom_Surface.hxx>
|
|
#include <Geom_TrimmedCurve.hxx>
|
|
#include <GeomAPI_ProjectPointOnSurf.hxx>
|
|
#include <gp_Cone.hxx>
|
|
#include <gp_Cylinder.hxx>
|
|
#include <gp_Lin.hxx>
|
|
#include <gp_Pnt.hxx>
|
|
#include <gp_Pnt2d.hxx>
|
|
#include <gp_Sphere.hxx>
|
|
#include <gp_Torus.hxx>
|
|
#include <gp_XYZ.hxx>
|
|
#include <IntTools_Context.hxx>
|
|
#include <IntTools_Range.hxx>
|
|
#include <IntTools_ShrunkRange.hxx>
|
|
#include <IntTools_Tools.hxx>
|
|
#include <Precision.hxx>
|
|
#include <TopAbs_Orientation.hxx>
|
|
#include <TopExp.hxx>
|
|
#include <TopExp_Explorer.hxx>
|
|
#include <TopoDS.hxx>
|
|
#include <TopoDS_Compound.hxx>
|
|
#include <TopoDS_CompSolid.hxx>
|
|
#include <TopoDS_Edge.hxx>
|
|
#include <TopoDS_Face.hxx>
|
|
#include <TopoDS_Shape.hxx>
|
|
#include <TopoDS_Shell.hxx>
|
|
#include <TopoDS_Solid.hxx>
|
|
#include <TopoDS_Vertex.hxx>
|
|
#include <TopoDS_Wire.hxx>
|
|
#include <TopTools_ShapeMapHasher.hxx>
|
|
#include <NCollection_IndexedMap.hxx>
|
|
#include <NCollection_Map.hxx>
|
|
#include <Message_Report.hxx>
|
|
#include <algorithm>
|
|
|
|
//
|
|
static double AngleWithRef(const gp_Dir& theD1, const gp_Dir& theD2, const gp_Dir& theDRef);
|
|
|
|
static bool FindFacePairs(const TopoDS_Edge& theE,
|
|
const NCollection_List<TopoDS_Shape>& thLF,
|
|
NCollection_List<BOPTools_CoupleOfShape>& theLCFF,
|
|
const occ::handle<IntTools_Context>& theContext);
|
|
static TopAbs_Orientation Orientation(const TopoDS_Edge& anE, const TopoDS_Face& aF);
|
|
|
|
static bool GetFaceDir(const TopoDS_Edge& aE,
|
|
const TopoDS_Face& aF,
|
|
const gp_Pnt& aP,
|
|
const double aT,
|
|
const gp_Dir& aDTgt,
|
|
const bool theSmallFaces,
|
|
gp_Dir& aDN,
|
|
gp_Dir& aDB,
|
|
const occ::handle<IntTools_Context>& theContext,
|
|
GeomAPI_ProjectPointOnSurf& aProjPL,
|
|
const double aDt);
|
|
static bool FindPointInFace(const TopoDS_Face& aF,
|
|
const gp_Pnt& aP,
|
|
gp_Dir& aDB,
|
|
gp_Pnt& aPOut,
|
|
const occ::handle<IntTools_Context>& theContext,
|
|
GeomAPI_ProjectPointOnSurf& aProjPL,
|
|
const double aDt,
|
|
const double aTolE);
|
|
static double MinStep3D(const TopoDS_Edge& theE1,
|
|
const TopoDS_Face& theF1,
|
|
const NCollection_List<BOPTools_CoupleOfShape>& theLCS,
|
|
const gp_Pnt& aP,
|
|
const occ::handle<IntTools_Context>& theContext,
|
|
bool& theSmallFaces);
|
|
|
|
//=================================================================================================
|
|
|
|
void BOPTools_AlgoTools::MakeConnexityBlocks(
|
|
const TopoDS_Shape& theS,
|
|
const TopAbs_ShapeEnum theConnectionType,
|
|
const TopAbs_ShapeEnum theElementType,
|
|
NCollection_List<NCollection_List<TopoDS_Shape>>& theLCB,
|
|
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>&
|
|
theConnectionMap)
|
|
{
|
|
// Map shapes to find connected elements
|
|
TopExp::MapShapesAndAncestors(theS, theConnectionType, theElementType, theConnectionMap);
|
|
// Fence map
|
|
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aMFence;
|
|
|
|
TopExp_Explorer aExp(theS, theElementType);
|
|
for (; aExp.More(); aExp.Next())
|
|
{
|
|
const TopoDS_Shape& aS = aExp.Current();
|
|
if (!aMFence.Add(aS))
|
|
{
|
|
continue;
|
|
}
|
|
// The block
|
|
NCollection_List<TopoDS_Shape> aLBlock;
|
|
// Start the block
|
|
aLBlock.Append(aS);
|
|
// Look for connected parts
|
|
NCollection_List<TopoDS_Shape>::Iterator aItB(aLBlock);
|
|
for (; aItB.More(); aItB.Next())
|
|
{
|
|
const TopoDS_Shape& aS1 = aItB.Value();
|
|
TopExp_Explorer aExpSS(aS1, theConnectionType);
|
|
for (; aExpSS.More(); aExpSS.Next())
|
|
{
|
|
const TopoDS_Shape& aSubS = aExpSS.Current();
|
|
const NCollection_List<TopoDS_Shape>& aLS = theConnectionMap.FindFromKey(aSubS);
|
|
NCollection_List<TopoDS_Shape>::Iterator aItLS(aLS);
|
|
for (; aItLS.More(); aItLS.Next())
|
|
{
|
|
const TopoDS_Shape& aS2 = aItLS.Value();
|
|
if (aMFence.Add(aS2))
|
|
aLBlock.Append(aS2);
|
|
}
|
|
}
|
|
}
|
|
// Add the block into result
|
|
theLCB.Append(aLBlock);
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void BOPTools_AlgoTools::MakeConnexityBlocks(const TopoDS_Shape& theS,
|
|
const TopAbs_ShapeEnum theConnectionType,
|
|
const TopAbs_ShapeEnum theElementType,
|
|
NCollection_List<TopoDS_Shape>& theLCB)
|
|
{
|
|
NCollection_List<NCollection_List<TopoDS_Shape>> aLBlocks;
|
|
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
|
|
aCMap;
|
|
BOPTools_AlgoTools::MakeConnexityBlocks(theS, theConnectionType, theElementType, aLBlocks, aCMap);
|
|
|
|
// Make compound from each block
|
|
NCollection_List<NCollection_List<TopoDS_Shape>>::Iterator aItB(aLBlocks);
|
|
for (; aItB.More(); aItB.Next())
|
|
{
|
|
const NCollection_List<TopoDS_Shape>& aLB = aItB.Value();
|
|
|
|
TopoDS_Compound aBlock;
|
|
BRep_Builder().MakeCompound(aBlock);
|
|
for (NCollection_List<TopoDS_Shape>::Iterator it(aLB); it.More(); it.Next())
|
|
BRep_Builder().Add(aBlock, it.Value());
|
|
|
|
theLCB.Append(aBlock);
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void BOPTools_AlgoTools::MakeConnexityBlocks(const NCollection_List<TopoDS_Shape>& theLS,
|
|
const TopAbs_ShapeEnum theConnectionType,
|
|
const TopAbs_ShapeEnum theElementType,
|
|
NCollection_List<BOPTools_ConnexityBlock>& theLCB)
|
|
{
|
|
BRep_Builder aBB;
|
|
// Make connexity blocks from start elements
|
|
TopoDS_Compound aCStart;
|
|
aBB.MakeCompound(aCStart);
|
|
|
|
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aMFence, aMNRegular;
|
|
|
|
NCollection_List<TopoDS_Shape>::Iterator aItL(theLS);
|
|
for (; aItL.More(); aItL.Next())
|
|
{
|
|
const TopoDS_Shape& aS = aItL.Value();
|
|
if (aMFence.Add(aS))
|
|
aBB.Add(aCStart, aS);
|
|
else
|
|
aMNRegular.Add(aS);
|
|
}
|
|
|
|
NCollection_List<NCollection_List<TopoDS_Shape>> aLCB;
|
|
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
|
|
aCMap;
|
|
BOPTools_AlgoTools::MakeConnexityBlocks(aCStart, theConnectionType, theElementType, aLCB, aCMap);
|
|
|
|
// Save the blocks and check their regularity
|
|
NCollection_List<NCollection_List<TopoDS_Shape>>::Iterator aItB(aLCB);
|
|
for (; aItB.More(); aItB.Next())
|
|
{
|
|
const NCollection_List<TopoDS_Shape>& aBlock = aItB.Value();
|
|
|
|
BOPTools_ConnexityBlock aCB;
|
|
NCollection_List<TopoDS_Shape>& aLCS = aCB.ChangeShapes();
|
|
|
|
bool bRegular = true;
|
|
for (NCollection_List<TopoDS_Shape>::Iterator it(aBlock); it.More(); it.Next())
|
|
{
|
|
TopoDS_Shape aS = it.Value();
|
|
if (aMNRegular.Contains(aS))
|
|
{
|
|
bRegular = false;
|
|
aS.Orientation(TopAbs_FORWARD);
|
|
aLCS.Append(aS);
|
|
aS.Orientation(TopAbs_REVERSED);
|
|
aLCS.Append(aS);
|
|
}
|
|
else
|
|
{
|
|
aLCS.Append(aS);
|
|
if (bRegular)
|
|
{
|
|
// Check if there are no multi-connected shapes
|
|
for (TopExp_Explorer ex(aS, theConnectionType); ex.More() && bRegular; ex.Next())
|
|
bRegular = (aCMap.FindFromKey(ex.Current()).Extent() == 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
aCB.SetRegular(bRegular);
|
|
theLCB.Append(aCB);
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
// function: OrientEdgesOnWire
|
|
// purpose: Reorient edges on wire for correct ordering
|
|
//=======================================================================
|
|
void BOPTools_AlgoTools::OrientEdgesOnWire(TopoDS_Shape& theWire)
|
|
{
|
|
// make vertex-edges connexity map
|
|
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
|
|
aVEMap;
|
|
TopExp::MapShapesAndAncestors(theWire, TopAbs_VERTEX, TopAbs_EDGE, aVEMap);
|
|
//
|
|
if (aVEMap.IsEmpty())
|
|
{
|
|
return;
|
|
}
|
|
//
|
|
BRep_Builder aBB;
|
|
// new wire
|
|
TopoDS_Wire aWire;
|
|
aBB.MakeWire(aWire);
|
|
// fence map
|
|
NCollection_Map<TopoDS_Shape> aMFence;
|
|
//
|
|
TopoDS_Iterator aIt(theWire);
|
|
for (; aIt.More(); aIt.Next())
|
|
{
|
|
const TopoDS_Edge& aEC = TopoDS::Edge(aIt.Value());
|
|
if (!aMFence.Add(aEC))
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
// add edge to a wire as it is
|
|
aBB.Add(aWire, aEC);
|
|
//
|
|
TopoDS_Vertex aV1, aV2;
|
|
TopExp::Vertices(aEC, aV1, aV2, true);
|
|
//
|
|
if (aV1.IsSame(aV2))
|
|
{
|
|
// closed edge, go to the next edge
|
|
continue;
|
|
}
|
|
//
|
|
// orient the adjacent edges
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
TopoDS_Shape aVC = !i ? aV1 : aV2;
|
|
//
|
|
for (;;)
|
|
{
|
|
const NCollection_List<TopoDS_Shape>& aLE = aVEMap.FindFromKey(aVC);
|
|
if (aLE.Extent() != 2)
|
|
{
|
|
// free vertex or multi-connexity, go to the next edge
|
|
break;
|
|
}
|
|
//
|
|
bool bStop = true;
|
|
//
|
|
NCollection_List<TopoDS_Shape>::Iterator aItLE(aLE);
|
|
for (; aItLE.More(); aItLE.Next())
|
|
{
|
|
const TopoDS_Edge& aEN = TopoDS::Edge(aItLE.Value());
|
|
if (aMFence.Contains(aEN))
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
TopoDS_Vertex aVN1, aVN2;
|
|
TopExp::Vertices(aEN, aVN1, aVN2, true);
|
|
if (aVN1.IsSame(aVN2))
|
|
{
|
|
// closed edge, go to the next edge
|
|
break;
|
|
}
|
|
//
|
|
// change orientation if necessary and go to the next edges
|
|
if ((!i && aVC.IsSame(aVN2)) || (i && aVC.IsSame(aVN1)))
|
|
{
|
|
aBB.Add(aWire, aEN);
|
|
}
|
|
else
|
|
{
|
|
aBB.Add(aWire, aEN.Reversed());
|
|
}
|
|
aMFence.Add(aEN);
|
|
aVC = aVC.IsSame(aVN1) ? aVN2 : aVN1;
|
|
bStop = false;
|
|
break;
|
|
}
|
|
//
|
|
if (bStop)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
theWire = aWire;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void BOPTools_AlgoTools::OrientFacesOnShell(TopoDS_Shape& aShell)
|
|
{
|
|
bool bIsProcessed1, bIsProcessed2;
|
|
int i, aNbE, aNbF, j;
|
|
TopAbs_Orientation anOrE1, anOrE2;
|
|
TopoDS_Face aF1x, aF2x;
|
|
TopoDS_Shape aShellNew;
|
|
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
|
|
aEFMap;
|
|
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> aProcessedFaces;
|
|
BRep_Builder aBB;
|
|
//
|
|
BOPTools_AlgoTools::MakeContainer(TopAbs_SHELL, aShellNew);
|
|
//
|
|
TopExp::MapShapesAndAncestors(aShell, TopAbs_EDGE, TopAbs_FACE, aEFMap);
|
|
aNbE = aEFMap.Extent();
|
|
//
|
|
// One seam edge in aEFMap contains 2 equivalent faces.
|
|
for (i = 1; i <= aNbE; ++i)
|
|
{
|
|
NCollection_List<TopoDS_Shape>& aLF = aEFMap.ChangeFromIndex(i);
|
|
aNbF = aLF.Extent();
|
|
if (aNbF > 1)
|
|
{
|
|
NCollection_List<TopoDS_Shape> aLFTmp;
|
|
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> aFM;
|
|
//
|
|
NCollection_List<TopoDS_Shape>::Iterator anIt(aLF);
|
|
for (; anIt.More(); anIt.Next())
|
|
{
|
|
const TopoDS_Shape& aF = anIt.Value();
|
|
if (!aFM.Contains(aF))
|
|
{
|
|
aFM.Add(aF);
|
|
aLFTmp.Append(aF);
|
|
}
|
|
}
|
|
aLF.Clear();
|
|
aLF = aLFTmp;
|
|
}
|
|
}
|
|
//
|
|
// Do
|
|
for (i = 1; i <= aNbE; ++i)
|
|
{
|
|
const TopoDS_Edge& aE = (*(TopoDS_Edge*)(&aEFMap.FindKey(i)));
|
|
if (BRep_Tool::Degenerated(aE))
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
const NCollection_List<TopoDS_Shape>& aLF = aEFMap.FindFromIndex(i);
|
|
aNbF = aLF.Extent();
|
|
if (aNbF != 2)
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
TopoDS_Face& aF1 = (*(TopoDS_Face*)(&aLF.First()));
|
|
TopoDS_Face& aF2 = (*(TopoDS_Face*)(&aLF.Last()));
|
|
//
|
|
bIsProcessed1 = aProcessedFaces.Contains(aF1);
|
|
bIsProcessed2 = aProcessedFaces.Contains(aF2);
|
|
if (bIsProcessed1 && bIsProcessed2)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!bIsProcessed1 && !bIsProcessed2)
|
|
{
|
|
aProcessedFaces.Add(aF1);
|
|
aBB.Add(aShellNew, aF1);
|
|
bIsProcessed1 = !bIsProcessed1;
|
|
}
|
|
//
|
|
aF1x = aF1;
|
|
if (bIsProcessed1)
|
|
{
|
|
j = aProcessedFaces.FindIndex(aF1);
|
|
aF1x = (*(TopoDS_Face*)(&aProcessedFaces.FindKey(j)));
|
|
}
|
|
//
|
|
aF2x = aF2;
|
|
if (bIsProcessed2)
|
|
{
|
|
j = aProcessedFaces.FindIndex(aF2);
|
|
aF2x = (*(TopoDS_Face*)(&aProcessedFaces.FindKey(j)));
|
|
}
|
|
//
|
|
anOrE1 = Orientation(aE, aF1x);
|
|
anOrE2 = Orientation(aE, aF2x);
|
|
//
|
|
if (bIsProcessed1 && !bIsProcessed2)
|
|
{
|
|
if (anOrE1 == anOrE2)
|
|
{
|
|
if (!BRep_Tool::IsClosed(aE, aF1) && !BRep_Tool::IsClosed(aE, aF2))
|
|
{
|
|
aF2.Reverse();
|
|
}
|
|
}
|
|
aProcessedFaces.Add(aF2);
|
|
aBB.Add(aShellNew, aF2);
|
|
}
|
|
else if (!bIsProcessed1 && bIsProcessed2)
|
|
{
|
|
if (anOrE1 == anOrE2)
|
|
{
|
|
if (!BRep_Tool::IsClosed(aE, aF1) && !BRep_Tool::IsClosed(aE, aF2))
|
|
{
|
|
aF1.Reverse();
|
|
}
|
|
}
|
|
aProcessedFaces.Add(aF1);
|
|
aBB.Add(aShellNew, aF1);
|
|
}
|
|
}
|
|
//
|
|
//
|
|
for (i = 1; i <= aNbE; ++i)
|
|
{
|
|
const TopoDS_Edge& aE = (*(TopoDS_Edge*)(&aEFMap.FindKey(i)));
|
|
if (BRep_Tool::Degenerated(aE))
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
const NCollection_List<TopoDS_Shape>& aLF = aEFMap.FindFromIndex(i);
|
|
aNbF = aLF.Extent();
|
|
if (aNbF != 2)
|
|
{
|
|
NCollection_List<TopoDS_Shape>::Iterator anIt(aLF);
|
|
for (; anIt.More(); anIt.Next())
|
|
{
|
|
const TopoDS_Face& aF = (*(TopoDS_Face*)(&anIt.Value()));
|
|
if (!aProcessedFaces.Contains(aF))
|
|
{
|
|
aProcessedFaces.Add(aF);
|
|
aBB.Add(aShellNew, aF);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
aShell = aShellNew;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
TopAbs_Orientation Orientation(const TopoDS_Edge& anE, const TopoDS_Face& aF)
|
|
{
|
|
TopAbs_Orientation anOr = TopAbs_INTERNAL;
|
|
|
|
TopExp_Explorer anExp;
|
|
anExp.Init(aF, TopAbs_EDGE);
|
|
for (; anExp.More(); anExp.Next())
|
|
{
|
|
const TopoDS_Edge& anEF1 = (*(TopoDS_Edge*)(&anExp.Current()));
|
|
if (anEF1.IsSame(anE))
|
|
{
|
|
anOr = anEF1.Orientation();
|
|
break;
|
|
}
|
|
}
|
|
return anOr;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function: MakeConnexityBlock.
|
|
// purpose:
|
|
//=======================================================================
|
|
void BOPTools_AlgoTools::MakeConnexityBlock(
|
|
NCollection_List<TopoDS_Shape>& theLFIn,
|
|
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher>& theMEAvoid,
|
|
NCollection_List<TopoDS_Shape>& theLCB,
|
|
const occ::handle<NCollection_BaseAllocator>& theAllocator)
|
|
{
|
|
int aNbF, aNbAdd1, aNbAdd, i;
|
|
TopExp_Explorer aExp;
|
|
NCollection_List<TopoDS_Shape>::Iterator aIt;
|
|
//
|
|
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> aMCB(100, theAllocator);
|
|
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> aMAdd(100, theAllocator);
|
|
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> aMAdd1(100, theAllocator);
|
|
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
|
|
aMEF(100, theAllocator);
|
|
//
|
|
// 1. aMEF
|
|
aNbF = theLFIn.Extent();
|
|
aIt.Initialize(theLFIn);
|
|
for (; aIt.More(); aIt.Next())
|
|
{
|
|
const TopoDS_Shape& aF = aIt.Value();
|
|
TopExp::MapShapesAndAncestors(aF, TopAbs_EDGE, TopAbs_FACE, aMEF);
|
|
}
|
|
//
|
|
// 2. aMCB
|
|
const TopoDS_Shape& aF1 = theLFIn.First();
|
|
aMAdd.Add(aF1);
|
|
//
|
|
for (;;)
|
|
{
|
|
aMAdd1.Clear();
|
|
aNbAdd = aMAdd.Extent();
|
|
for (i = 1; i <= aNbAdd; ++i)
|
|
{
|
|
const TopoDS_Shape& aF = aMAdd(i);
|
|
//
|
|
// aMAdd1.Clear();
|
|
aExp.Init(aF, TopAbs_EDGE);
|
|
for (; aExp.More(); aExp.Next())
|
|
{
|
|
const TopoDS_Shape& aE = aExp.Current();
|
|
if (theMEAvoid.Contains(aE))
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
const NCollection_List<TopoDS_Shape>& aLF = aMEF.FindFromKey(aE);
|
|
aIt.Initialize(aLF);
|
|
for (; aIt.More(); aIt.Next())
|
|
{
|
|
const TopoDS_Shape& aFx = aIt.Value();
|
|
if (aFx.IsSame(aF))
|
|
{
|
|
continue;
|
|
}
|
|
if (aMCB.Contains(aFx))
|
|
{
|
|
continue;
|
|
}
|
|
aMAdd1.Add(aFx);
|
|
}
|
|
} // for (; aExp.More(); aExp.Next()){
|
|
aMCB.Add(aF);
|
|
} // for (i=1; i<=aNbAdd; ++i) {
|
|
//
|
|
aNbAdd1 = aMAdd1.Extent();
|
|
if (!aNbAdd1)
|
|
{
|
|
break;
|
|
}
|
|
//
|
|
aMAdd.Clear();
|
|
for (i = 1; i <= aNbAdd1; ++i)
|
|
{
|
|
const TopoDS_Shape& aFAdd = aMAdd1(i);
|
|
aMAdd.Add(aFAdd);
|
|
}
|
|
//
|
|
} // while(1) {
|
|
|
|
//
|
|
aNbF = aMCB.Extent();
|
|
for (i = 1; i <= aNbF; ++i)
|
|
{
|
|
const TopoDS_Shape& aF = aMCB(i);
|
|
theLCB.Append(aF);
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
TopAbs_State BOPTools_AlgoTools::ComputeStateByOnePoint(
|
|
const TopoDS_Shape& theS,
|
|
const TopoDS_Solid& theRef,
|
|
const double theTol,
|
|
const occ::handle<IntTools_Context>& theContext)
|
|
{
|
|
TopAbs_State aState = TopAbs_UNKNOWN;
|
|
TopAbs_ShapeEnum aType = theS.ShapeType();
|
|
|
|
switch (aType)
|
|
{
|
|
case TopAbs_VERTEX:
|
|
aState = ComputeState(TopoDS::Vertex(theS), theRef, theTol, theContext);
|
|
break;
|
|
case TopAbs_EDGE:
|
|
aState = ComputeState(TopoDS::Edge(theS), theRef, theTol, theContext);
|
|
break;
|
|
case TopAbs_FACE: {
|
|
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> aBounds;
|
|
TopExp::MapShapes(theRef, TopAbs_EDGE, aBounds);
|
|
aState = ComputeState(TopoDS::Face(theS), theRef, theTol, aBounds, theContext);
|
|
break;
|
|
}
|
|
default: {
|
|
TopoDS_Iterator it(theS);
|
|
if (it.More())
|
|
ComputeStateByOnePoint(it.Value(), theRef, theTol, theContext);
|
|
break;
|
|
}
|
|
}
|
|
return aState;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
TopAbs_State BOPTools_AlgoTools::ComputeState(
|
|
const TopoDS_Face& theF,
|
|
const TopoDS_Solid& theRef,
|
|
const double theTol,
|
|
const NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher>& theBounds,
|
|
const occ::handle<IntTools_Context>& theContext)
|
|
{
|
|
TopAbs_State aState = TopAbs_UNKNOWN;
|
|
|
|
// Try to find the edge on the face which does not
|
|
// belong to the solid and classify the middle point of that
|
|
// edge relatively solid.
|
|
TopExp_Explorer aExp(theF, TopAbs_EDGE);
|
|
for (; aExp.More(); aExp.Next())
|
|
{
|
|
const TopoDS_Edge& aSE = (*(TopoDS_Edge*)(&aExp.Current()));
|
|
if (BRep_Tool::Degenerated(aSE))
|
|
continue;
|
|
|
|
if (!theBounds.Contains(aSE))
|
|
{
|
|
aState = BOPTools_AlgoTools::ComputeState(aSE, theRef, theTol, theContext);
|
|
return aState;
|
|
}
|
|
}
|
|
|
|
// All edges of the face are on the solid.
|
|
// Get point inside the face and classify it relatively solid.
|
|
gp_Pnt aP3D;
|
|
gp_Pnt2d aP2D;
|
|
int iErr = BOPTools_AlgoTools3D::PointInFace(theF, aP3D, aP2D, theContext);
|
|
if (iErr != 0)
|
|
{
|
|
// Hatcher fails to find the point -> get point near some edge
|
|
aExp.Init(theF, TopAbs_EDGE);
|
|
for (; aExp.More() && iErr != 0; aExp.Next())
|
|
{
|
|
const TopoDS_Edge& aSE = TopoDS::Edge(aExp.Current());
|
|
if (BRep_Tool::Degenerated(aSE))
|
|
continue;
|
|
|
|
iErr = BOPTools_AlgoTools3D::PointNearEdge(aSE, theF, aP2D, aP3D, theContext);
|
|
}
|
|
}
|
|
|
|
if (iErr == 0)
|
|
aState = BOPTools_AlgoTools::ComputeState(aP3D, theRef, theTol, theContext);
|
|
|
|
return aState;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
TopAbs_State BOPTools_AlgoTools::ComputeState(const TopoDS_Vertex& theV,
|
|
const TopoDS_Solid& theRef,
|
|
const double theTol,
|
|
const occ::handle<IntTools_Context>& theContext)
|
|
{
|
|
TopAbs_State aState;
|
|
gp_Pnt aP3D;
|
|
//
|
|
aP3D = BRep_Tool::Pnt(theV);
|
|
aState = BOPTools_AlgoTools::ComputeState(aP3D, theRef, theTol, theContext);
|
|
return aState;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
TopAbs_State BOPTools_AlgoTools::ComputeState(const TopoDS_Edge& theE,
|
|
const TopoDS_Solid& theRef,
|
|
const double theTol,
|
|
const occ::handle<IntTools_Context>& theContext)
|
|
{
|
|
double aT1, aT2, aT = 0.;
|
|
TopAbs_State aState;
|
|
occ::handle<Geom_Curve> aC3D;
|
|
gp_Pnt aP3D;
|
|
//
|
|
aC3D = BRep_Tool::Curve(theE, aT1, aT2);
|
|
//
|
|
if (aC3D.IsNull())
|
|
{
|
|
// it means that we are in degenerated edge
|
|
const TopoDS_Vertex& aV = TopExp::FirstVertex(theE);
|
|
if (aV.IsNull())
|
|
{
|
|
return TopAbs_UNKNOWN;
|
|
}
|
|
aP3D = BRep_Tool::Pnt(aV);
|
|
}
|
|
else
|
|
{ // usual case
|
|
bool bF2Inf, bL2Inf;
|
|
double dT = 10.;
|
|
//
|
|
bF2Inf = Precision::IsNegativeInfinite(aT1);
|
|
bL2Inf = Precision::IsPositiveInfinite(aT2);
|
|
//
|
|
if (bF2Inf && !bL2Inf)
|
|
{
|
|
aT = aT2 - dT;
|
|
}
|
|
else if (!bF2Inf && bL2Inf)
|
|
{
|
|
aT = aT1 + dT;
|
|
}
|
|
else if (bF2Inf && bL2Inf)
|
|
{
|
|
aT = 0.;
|
|
}
|
|
else
|
|
{
|
|
aT = IntTools_Tools::IntermediatePoint(aT1, aT2);
|
|
}
|
|
aC3D->D0(aT, aP3D);
|
|
}
|
|
//
|
|
aState = BOPTools_AlgoTools::ComputeState(aP3D, theRef, theTol, theContext);
|
|
//
|
|
return aState;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
TopAbs_State BOPTools_AlgoTools::ComputeState(const gp_Pnt& theP,
|
|
const TopoDS_Solid& theRef,
|
|
const double theTol,
|
|
const occ::handle<IntTools_Context>& theContext)
|
|
{
|
|
TopAbs_State aState;
|
|
//
|
|
BRepClass3d_SolidClassifier& aSC = theContext->SolidClassifier(theRef);
|
|
aSC.Perform(theP, theTol);
|
|
//
|
|
aState = aSC.State();
|
|
//
|
|
return aState;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::IsInternalFace(
|
|
const TopoDS_Face& theFace,
|
|
const TopoDS_Solid& theSolid,
|
|
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>&
|
|
theMEF,
|
|
const double theTol,
|
|
const occ::handle<IntTools_Context>& theContext)
|
|
{
|
|
bool bDegenerated;
|
|
TopAbs_Orientation aOr;
|
|
TopoDS_Edge aE1;
|
|
TopExp_Explorer aExp;
|
|
NCollection_List<TopoDS_Shape>::Iterator aItF;
|
|
//
|
|
// For all invoked functions: [::IsInternalFace(...)]
|
|
// the returned value iRet means:
|
|
// iRet=0; - state is not IN
|
|
// iRet=1; - state is IN
|
|
// iRet=2; - state can not be found by the method of angles
|
|
int iRet = 0;
|
|
// 1 Try to find an edge from theFace in theMEF
|
|
aExp.Init(theFace, TopAbs_EDGE);
|
|
for (; aExp.More(); aExp.Next())
|
|
{
|
|
const TopoDS_Edge& aE = (*(TopoDS_Edge*)(&aExp.Current()));
|
|
if (!theMEF.Contains(aE))
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
aOr = aE.Orientation();
|
|
if (aOr == TopAbs_INTERNAL)
|
|
{
|
|
continue;
|
|
}
|
|
bDegenerated = BRep_Tool::Degenerated(aE);
|
|
if (bDegenerated)
|
|
{
|
|
continue;
|
|
}
|
|
// aE
|
|
NCollection_List<TopoDS_Shape>& aLF = theMEF.ChangeFromKey(aE);
|
|
int aNbF = aLF.Extent();
|
|
if (aNbF == 1)
|
|
{
|
|
// aE is internal edge on aLF.First()
|
|
const TopoDS_Face& aF1 = (*(TopoDS_Face*)(&aLF.First()));
|
|
BOPTools_AlgoTools::GetEdgeOnFace(aE, aF1, aE1);
|
|
if (aE1.Orientation() != TopAbs_INTERNAL)
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
iRet = BOPTools_AlgoTools::IsInternalFace(theFace, aE, aF1, aF1, theContext);
|
|
break;
|
|
}
|
|
//
|
|
else if (aNbF == 2)
|
|
{
|
|
const TopoDS_Face& aF1 = (*(TopoDS_Face*)(&aLF.First()));
|
|
const TopoDS_Face& aF2 = (*(TopoDS_Face*)(&aLF.Last()));
|
|
iRet = BOPTools_AlgoTools::IsInternalFace(theFace, aE, aF1, aF2, theContext);
|
|
if (iRet != 2)
|
|
break;
|
|
}
|
|
} // for(; aExp.More(); aExp.Next()) {
|
|
//
|
|
if (aExp.More() && iRet != 2)
|
|
{
|
|
return iRet == 1;
|
|
}
|
|
//
|
|
//========================================
|
|
// 2. Classify face using classifier
|
|
//
|
|
TopAbs_State aState;
|
|
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> aBounds;
|
|
//
|
|
TopExp::MapShapes(theSolid, TopAbs_EDGE, aBounds);
|
|
//
|
|
aState = BOPTools_AlgoTools::ComputeState(theFace, theSolid, theTol, aBounds, theContext);
|
|
return aState == TopAbs_IN;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
int BOPTools_AlgoTools::IsInternalFace(const TopoDS_Face& theFace,
|
|
const TopoDS_Edge& theEdge,
|
|
NCollection_List<TopoDS_Shape>& theLF,
|
|
const occ::handle<IntTools_Context>& theContext)
|
|
{
|
|
int aNbF, iRet;
|
|
//
|
|
iRet = 0;
|
|
//
|
|
aNbF = theLF.Extent();
|
|
if (aNbF == 2)
|
|
{
|
|
const TopoDS_Face& aF1 = (*(TopoDS_Face*)(&theLF.First()));
|
|
const TopoDS_Face& aF2 = (*(TopoDS_Face*)(&theLF.Last()));
|
|
iRet = BOPTools_AlgoTools::IsInternalFace(theFace, theEdge, aF1, aF2, theContext);
|
|
return iRet;
|
|
}
|
|
//
|
|
else
|
|
{
|
|
NCollection_List<BOPTools_CoupleOfShape> aLCFF;
|
|
NCollection_List<BOPTools_CoupleOfShape>::Iterator aIt;
|
|
//
|
|
FindFacePairs(theEdge, theLF, aLCFF, theContext);
|
|
//
|
|
aIt.Initialize(aLCFF);
|
|
for (; aIt.More(); aIt.Next())
|
|
{
|
|
BOPTools_CoupleOfShape& aCSFF = aIt.ChangeValue();
|
|
//
|
|
const TopoDS_Face& aF1 = (*(TopoDS_Face*)(&aCSFF.Shape1()));
|
|
const TopoDS_Face& aF2 = (*(TopoDS_Face*)(&aCSFF.Shape2()));
|
|
iRet = BOPTools_AlgoTools::IsInternalFace(theFace, theEdge, aF1, aF2, theContext);
|
|
if (iRet)
|
|
{
|
|
return iRet;
|
|
}
|
|
}
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
int BOPTools_AlgoTools::IsInternalFace(const TopoDS_Face& theFace,
|
|
const TopoDS_Edge& theEdge,
|
|
const TopoDS_Face& theFace1,
|
|
const TopoDS_Face& theFace2,
|
|
const occ::handle<IntTools_Context>& theContext)
|
|
{
|
|
TopoDS_Edge aE1, aE2;
|
|
TopoDS_Face aFOff;
|
|
NCollection_List<BOPTools_CoupleOfShape> theLCSOff;
|
|
BOPTools_CoupleOfShape aCS1, aCS2;
|
|
//
|
|
BOPTools_AlgoTools::GetEdgeOnFace(theEdge, theFace1, aE1);
|
|
if (aE1.Orientation() == TopAbs_INTERNAL)
|
|
{
|
|
aE2 = aE1;
|
|
aE1.Orientation(TopAbs_FORWARD);
|
|
aE2.Orientation(TopAbs_REVERSED);
|
|
}
|
|
else if (theFace1 == theFace2)
|
|
{
|
|
aE2 = aE1;
|
|
aE1.Orientation(TopAbs_FORWARD);
|
|
aE2.Orientation(TopAbs_REVERSED);
|
|
}
|
|
else
|
|
{
|
|
BOPTools_AlgoTools::GetEdgeOnFace(theEdge, theFace2, aE2);
|
|
}
|
|
//
|
|
aCS1.SetShape1(theEdge);
|
|
aCS1.SetShape2(theFace);
|
|
theLCSOff.Append(aCS1);
|
|
//
|
|
aCS2.SetShape1(aE2);
|
|
aCS2.SetShape2(theFace2);
|
|
theLCSOff.Append(aCS2);
|
|
//
|
|
int iRet = 0; // theFace is not internal
|
|
bool isDone = GetFaceOff(aE1, theFace1, theLCSOff, aFOff, theContext);
|
|
if (!isDone)
|
|
// error, unable to classify face by this edge
|
|
iRet = 2;
|
|
else if (theFace.IsEqual(aFOff))
|
|
// theFace is internal
|
|
iRet = 1;
|
|
|
|
return iRet;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::GetFaceOff(const TopoDS_Edge& theE1,
|
|
const TopoDS_Face& theF1,
|
|
NCollection_List<BOPTools_CoupleOfShape>& theLCSOff,
|
|
TopoDS_Face& theFOff,
|
|
const occ::handle<IntTools_Context>& theContext)
|
|
{
|
|
bool bRet, bIsComputed;
|
|
double aT, aT1, aT2, aAngle, aTwoPI, aAngleMin, aDt3D;
|
|
double aUmin, aUsup, aVmin, aVsup;
|
|
gp_Pnt aPx;
|
|
gp_Dir aDN1, aDN2, aDBF, aDBF2, aDTF;
|
|
gp_Vec aVTgt;
|
|
TopAbs_Orientation aOr;
|
|
occ::handle<Geom_Curve> aC3D;
|
|
occ::handle<Geom_Plane> aPL;
|
|
NCollection_List<BOPTools_CoupleOfShape>::Iterator aIt;
|
|
GeomAPI_ProjectPointOnSurf aProjPL;
|
|
//
|
|
aAngleMin = 100.;
|
|
aTwoPI = M_PI + M_PI;
|
|
aC3D = BRep_Tool::Curve(theE1, aT1, aT2);
|
|
aT = BOPTools_AlgoTools2D::IntermediatePoint(aT1, aT2);
|
|
aC3D->D0(aT, aPx);
|
|
//
|
|
BOPTools_AlgoTools2D::EdgeTangent(theE1, aT, aVTgt);
|
|
gp_Dir aDTgt(aVTgt), aDTgt2;
|
|
aOr = theE1.Orientation();
|
|
//
|
|
aPL = new Geom_Plane(aPx, aDTgt);
|
|
aPL->Bounds(aUmin, aUsup, aVmin, aVsup);
|
|
aProjPL.Init(aPL, aUmin, aUsup, aVmin, aVsup);
|
|
//
|
|
bool bSmallFaces = false;
|
|
aDt3D = MinStep3D(theE1, theF1, theLCSOff, aPx, theContext, bSmallFaces);
|
|
bIsComputed =
|
|
GetFaceDir(theE1, theF1, aPx, aT, aDTgt, bSmallFaces, aDN1, aDBF, theContext, aProjPL, aDt3D);
|
|
if (!bIsComputed)
|
|
{
|
|
#ifdef OCCT_DEBUG
|
|
std::cout << "BOPTools_AlgoTools::GetFaceOff(): incorrect computation of bi-normal direction."
|
|
<< std::endl;
|
|
#endif
|
|
}
|
|
//
|
|
aDTF = aDN1 ^ aDBF;
|
|
//
|
|
// The difference between faces should be obvious enough
|
|
// to guarantee the correctness of the classification
|
|
constexpr double anAngleCriteria = Precision::Confusion();
|
|
|
|
bRet = true;
|
|
aIt.Initialize(theLCSOff);
|
|
for (; aIt.More(); aIt.Next())
|
|
{
|
|
const BOPTools_CoupleOfShape& aCS = aIt.Value();
|
|
const TopoDS_Edge& aE2 = (*(TopoDS_Edge*)(&aCS.Shape1()));
|
|
const TopoDS_Face& aF2 = (*(TopoDS_Face*)(&aCS.Shape2()));
|
|
//
|
|
aDTgt2 = (aE2.Orientation() == aOr) ? aDTgt : aDTgt.Reversed();
|
|
bIsComputed =
|
|
GetFaceDir(aE2, aF2, aPx, aT, aDTgt2, bSmallFaces, aDN2, aDBF2, theContext, aProjPL, aDt3D);
|
|
if (!bIsComputed)
|
|
{
|
|
#ifdef OCCT_DEBUG
|
|
std::cout << "BOPTools_AlgoTools::GetFaceOff(): incorrect computation of bi-normal direction."
|
|
<< std::endl;
|
|
#endif
|
|
}
|
|
// Angle
|
|
aAngle = AngleWithRef(aDBF, aDBF2, aDTF);
|
|
//
|
|
if (std::abs(aAngle) < Precision::Angular())
|
|
{
|
|
if (aF2 == theF1)
|
|
{
|
|
aAngle = M_PI;
|
|
}
|
|
else if (aF2.IsSame(theF1))
|
|
{
|
|
aAngle = aTwoPI;
|
|
}
|
|
}
|
|
//
|
|
if (std::abs(aAngle) < anAngleCriteria || std::abs(aAngle - aAngleMin) < anAngleCriteria)
|
|
{
|
|
// the minimal angle can not be found
|
|
bRet = false;
|
|
}
|
|
//
|
|
if (aAngle < 0.)
|
|
{
|
|
aAngle = aTwoPI + aAngle;
|
|
}
|
|
//
|
|
if (aAngle < aAngleMin)
|
|
{
|
|
aAngleMin = aAngle;
|
|
theFOff = aF2;
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::GetEdgeOff(const TopoDS_Edge& theE1,
|
|
const TopoDS_Face& theF2,
|
|
TopoDS_Edge& theE2)
|
|
{
|
|
bool bFound;
|
|
TopAbs_Orientation aOr1, aOr1C, aOr2;
|
|
TopExp_Explorer anExp;
|
|
//
|
|
bFound = false;
|
|
aOr1 = theE1.Orientation();
|
|
aOr1C = TopAbs::Reverse(aOr1);
|
|
//
|
|
anExp.Init(theF2, TopAbs_EDGE);
|
|
for (; anExp.More(); anExp.Next())
|
|
{
|
|
const TopoDS_Edge& aEF2 = (*(TopoDS_Edge*)(&anExp.Current()));
|
|
if (aEF2.IsSame(theE1))
|
|
{
|
|
aOr2 = aEF2.Orientation();
|
|
if (aOr2 == aOr1C)
|
|
{
|
|
theE2 = aEF2;
|
|
bFound = !bFound;
|
|
return bFound;
|
|
}
|
|
}
|
|
}
|
|
return bFound;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::AreFacesSameDomain(const TopoDS_Face& theF1,
|
|
const TopoDS_Face& theF2,
|
|
const occ::handle<IntTools_Context>& theContext,
|
|
const double theFuzz)
|
|
{
|
|
bool bFacesSD = false;
|
|
|
|
// The idea is to find a point inside the first face
|
|
// and check its validity for the second face.
|
|
// If valid - the faces are same domain.
|
|
|
|
gp_Pnt aP1;
|
|
gp_Pnt2d aP2D1;
|
|
// Find point inside the first face
|
|
int iErr = BOPTools_AlgoTools3D::PointInFace(theF1, aP1, aP2D1, theContext);
|
|
|
|
if (iErr != 0)
|
|
{
|
|
// unable to find the point
|
|
return bFacesSD;
|
|
}
|
|
|
|
// Check validity of the point for second face
|
|
|
|
// Compute the tolerance to check the validity -
|
|
// sum of tolerance of faces and fuzzy tolerance
|
|
|
|
// Compute the tolerance of the faces, taking into account the deviation
|
|
// of the edges from the surfaces
|
|
double aTolF1 = BRep_Tool::Tolerance(theF1), aTolF2 = BRep_Tool::Tolerance(theF2);
|
|
|
|
// Find maximal tolerance of edges.
|
|
// The faces should have the same boundaries, thus
|
|
// it does not matter which face to explore.
|
|
{
|
|
double aTolEMax = -1.;
|
|
TopExp_Explorer anExpE(theF1, TopAbs_EDGE);
|
|
for (; anExpE.More(); anExpE.Next())
|
|
{
|
|
const TopoDS_Edge& aE = TopoDS::Edge(anExpE.Current());
|
|
if (!BRep_Tool::Degenerated(aE))
|
|
{
|
|
double aTolE = BRep_Tool::Tolerance(aE);
|
|
if (aTolE > aTolEMax)
|
|
aTolEMax = aTolE;
|
|
}
|
|
}
|
|
if (aTolEMax > aTolF1)
|
|
aTolF1 = aTolEMax;
|
|
if (aTolEMax > aTolF2)
|
|
aTolF2 = aTolEMax;
|
|
}
|
|
|
|
// Checking criteria
|
|
double aTol = aTolF1 + aTolF2 + std::max(theFuzz, Precision::Confusion());
|
|
|
|
// Project and classify the point on second face
|
|
bFacesSD = theContext->IsValidPointForFace(aP1, theF2, aTol);
|
|
|
|
return bFacesSD;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
int BOPTools_AlgoTools::Sense(const TopoDS_Face& theF1,
|
|
const TopoDS_Face& theF2,
|
|
const occ::handle<IntTools_Context>& theContext)
|
|
{
|
|
int iSense = 0;
|
|
gp_Dir aDNF1, aDNF2;
|
|
TopoDS_Edge aE1, aE2;
|
|
TopExp_Explorer aExp;
|
|
//
|
|
aExp.Init(theF1, TopAbs_EDGE);
|
|
for (; aExp.More(); aExp.Next())
|
|
{
|
|
aE1 = (*(TopoDS_Edge*)(&aExp.Current()));
|
|
if (!BRep_Tool::Degenerated(aE1))
|
|
{
|
|
if (!BRep_Tool::IsClosed(aE1, theF1))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
aExp.Init(theF2, TopAbs_EDGE);
|
|
for (; aExp.More(); aExp.Next())
|
|
{
|
|
aE2 = (*(TopoDS_Edge*)(&aExp.Current()));
|
|
if (!BRep_Tool::Degenerated(aE2))
|
|
{
|
|
if (!BRep_Tool::IsClosed(aE2, theF2))
|
|
{
|
|
if (aE2.IsSame(aE1))
|
|
{
|
|
iSense = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
if (!iSense)
|
|
{
|
|
return iSense;
|
|
}
|
|
//
|
|
BOPTools_AlgoTools3D::GetNormalToFaceOnEdge(aE1, theF1, aDNF1, theContext);
|
|
BOPTools_AlgoTools3D::GetNormalToFaceOnEdge(aE2, theF2, aDNF2, theContext);
|
|
//
|
|
iSense = BOPTools_AlgoTools3D::SenseFlag(aDNF1, aDNF2);
|
|
//
|
|
return iSense;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::IsSplitToReverse(const TopoDS_Shape& theSp,
|
|
const TopoDS_Shape& theSr,
|
|
const occ::handle<IntTools_Context>& theContext,
|
|
int* theError)
|
|
{
|
|
bool bRet;
|
|
TopAbs_ShapeEnum aType;
|
|
//
|
|
bRet = false;
|
|
//
|
|
aType = theSp.ShapeType();
|
|
switch (aType)
|
|
{
|
|
case TopAbs_EDGE: {
|
|
const TopoDS_Edge& aESp = (*(TopoDS_Edge*)(&theSp));
|
|
const TopoDS_Edge& aESr = (*(TopoDS_Edge*)(&theSr));
|
|
bRet = BOPTools_AlgoTools::IsSplitToReverse(aESp, aESr, theContext, theError);
|
|
}
|
|
break;
|
|
//
|
|
case TopAbs_FACE: {
|
|
const TopoDS_Face& aFSp = (*(TopoDS_Face*)(&theSp));
|
|
const TopoDS_Face& aFSr = (*(TopoDS_Face*)(&theSr));
|
|
bRet = BOPTools_AlgoTools::IsSplitToReverse(aFSp, aFSr, theContext, theError);
|
|
}
|
|
break;
|
|
//
|
|
default:
|
|
if (theError)
|
|
*theError = 100;
|
|
break;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::IsSplitToReverseWithWarn(const TopoDS_Shape& theSplit,
|
|
const TopoDS_Shape& theShape,
|
|
const occ::handle<IntTools_Context>& theContext,
|
|
const occ::handle<Message_Report>& theReport)
|
|
{
|
|
int anErr;
|
|
bool isToReverse = BOPTools_AlgoTools::IsSplitToReverse(theSplit, theShape, theContext, &anErr);
|
|
if (anErr != 0 && !theReport.IsNull())
|
|
{
|
|
// The error occurred during the check.
|
|
// Add warning to the report, storing the shapes into the warning.
|
|
TopoDS_Compound aWC;
|
|
BRep_Builder().MakeCompound(aWC);
|
|
BRep_Builder().Add(aWC, theSplit);
|
|
BRep_Builder().Add(aWC, theShape);
|
|
theReport->AddAlert(Message_Warning, new BOPAlgo_AlertUnableToOrientTheShape(aWC));
|
|
}
|
|
return isToReverse;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::IsSplitToReverse(const TopoDS_Face& theFSp,
|
|
const TopoDS_Face& theFSr,
|
|
const occ::handle<IntTools_Context>& theContext,
|
|
int* theError)
|
|
{
|
|
// Set OK error status
|
|
if (theError)
|
|
*theError = 0;
|
|
|
|
// Compare surfaces
|
|
occ::handle<Geom_Surface> aSFSp = BRep_Tool::Surface(theFSp);
|
|
occ::handle<Geom_Surface> aSFOr = BRep_Tool::Surface(theFSr);
|
|
if (aSFSp == aSFOr)
|
|
{
|
|
return theFSp.Orientation() != theFSr.Orientation();
|
|
}
|
|
//
|
|
bool bDone = false;
|
|
// Find the point inside the split face
|
|
gp_Pnt aPFSp;
|
|
gp_Pnt2d aP2DFSp;
|
|
//
|
|
// Error status
|
|
int iErr;
|
|
// Use the hatcher to find the point in the middle of the face
|
|
iErr = BOPTools_AlgoTools3D::PointInFace(theFSp, aPFSp, aP2DFSp, theContext);
|
|
if (iErr)
|
|
{
|
|
// Hatcher has failed to find a point.
|
|
// Try to get the point near some not closed and
|
|
// not degenerated edge on the split face.
|
|
TopExp_Explorer anExp(theFSp, TopAbs_EDGE);
|
|
for (; anExp.More(); anExp.Next())
|
|
{
|
|
const TopoDS_Edge& aESp = (*(TopoDS_Edge*)(&anExp.Current()));
|
|
if (!BRep_Tool::Degenerated(aESp) && !BRep_Tool::IsClosed(aESp, theFSp))
|
|
{
|
|
iErr = BOPTools_AlgoTools3D::PointNearEdge(aESp, theFSp, aP2DFSp, aPFSp, theContext);
|
|
if (!iErr)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
if (!anExp.More())
|
|
{
|
|
if (theError)
|
|
*theError = 1;
|
|
// The point has not been found.
|
|
return bDone;
|
|
}
|
|
}
|
|
//
|
|
// Compute normal direction of the split face
|
|
gp_Dir aDNFSp;
|
|
bDone = BOPTools_AlgoTools3D::GetNormalToSurface(aSFSp, aP2DFSp.X(), aP2DFSp.Y(), aDNFSp);
|
|
if (!bDone)
|
|
{
|
|
if (theError)
|
|
*theError = 2;
|
|
return bDone;
|
|
}
|
|
//
|
|
if (theFSp.Orientation() == TopAbs_REVERSED)
|
|
{
|
|
aDNFSp.Reverse();
|
|
}
|
|
//
|
|
// Project the point from the split face on the original face
|
|
// to find its UV coordinates
|
|
GeomAPI_ProjectPointOnSurf& aProjector = theContext->ProjPS(theFSr);
|
|
aProjector.Perform(aPFSp);
|
|
bDone = (aProjector.NbPoints() > 0);
|
|
if (!bDone)
|
|
{
|
|
if (theError)
|
|
*theError = 3;
|
|
return bDone;
|
|
}
|
|
// UV coordinates of the point on the original face
|
|
double aU, aV;
|
|
aProjector.LowerDistanceParameters(aU, aV);
|
|
//
|
|
// Compute normal direction for the original face in this point
|
|
gp_Dir aDNFOr;
|
|
bDone = BOPTools_AlgoTools3D::GetNormalToSurface(aSFOr, aU, aV, aDNFOr);
|
|
if (!bDone)
|
|
{
|
|
if (theError)
|
|
*theError = 4;
|
|
return bDone;
|
|
}
|
|
//
|
|
if (theFSr.Orientation() == TopAbs_REVERSED)
|
|
{
|
|
aDNFOr.Reverse();
|
|
}
|
|
//
|
|
// compare the normals
|
|
double aCos = aDNFSp * aDNFOr;
|
|
return (aCos < 0.);
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::IsSplitToReverse(const TopoDS_Edge& theESp,
|
|
const TopoDS_Edge& theEOr,
|
|
const occ::handle<IntTools_Context>& theContext,
|
|
int* theError)
|
|
{
|
|
// The idea is to compare the tangent vectors of two edges computed in
|
|
// the same point. Thus, we need to take the point on split edge (since it is
|
|
// shorter) and project it onto original edge to find corresponding parameter.
|
|
|
|
if (BRep_Tool::Degenerated(theESp) || BRep_Tool::Degenerated(theEOr))
|
|
{
|
|
if (theError)
|
|
*theError = 1;
|
|
return false;
|
|
}
|
|
|
|
// Set OK error status
|
|
if (theError)
|
|
*theError = 0;
|
|
|
|
// Get the curves from the edges
|
|
double f, l;
|
|
occ::handle<Geom_Curve> aCSp = BRep_Tool::Curve(theESp, f, l);
|
|
occ::handle<Geom_Curve> aCOr = BRep_Tool::Curve(theEOr, f, l);
|
|
|
|
// If the curves are the same, compare orientations only
|
|
if (aCSp == aCOr)
|
|
return theESp.Orientation() != theEOr.Orientation();
|
|
|
|
// Find valid range of the split edge, to ensure that the point for computing
|
|
// tangent vectors will be inside both edges.
|
|
if (!BRepLib::FindValidRange(theESp, f, l))
|
|
BRep_Tool::Range(theESp, f, l);
|
|
|
|
// Error code
|
|
int anErr = 0;
|
|
// Try a few sample points on the split edge until first valid found
|
|
const int aNbP = 11;
|
|
const double aDT = (l - f) / aNbP;
|
|
for (int i = 1; i < aNbP; ++i)
|
|
{
|
|
const double aTm = f + i * aDT;
|
|
// Compute tangent vector on split edge
|
|
gp_Vec aVSpTgt;
|
|
if (!BOPTools_AlgoTools2D::EdgeTangent(theESp, aTm, aVSpTgt))
|
|
{
|
|
// Unable to compute the tangent vector on the split edge
|
|
// in this point -> take the next point
|
|
anErr = 2;
|
|
continue;
|
|
}
|
|
|
|
// Find corresponding parameter on the original edge
|
|
double aTmOr;
|
|
if (!theContext->ProjectPointOnEdge(aCSp->Value(aTm), theEOr, aTmOr))
|
|
{
|
|
// Unable to project the point inside the split edge
|
|
// onto the original edge -> take the next point
|
|
anErr = 3;
|
|
continue;
|
|
}
|
|
|
|
// Compute tangent vector on original edge
|
|
gp_Vec aVOrTgt;
|
|
if (!BOPTools_AlgoTools2D::EdgeTangent(theEOr, aTmOr, aVOrTgt))
|
|
{
|
|
// Unable to compute the tangent vector on the original edge
|
|
// in this point -> take the next point
|
|
anErr = 4;
|
|
continue;
|
|
}
|
|
|
|
// Compute the Dot product
|
|
double aCos = aVSpTgt.Dot(aVOrTgt);
|
|
return (aCos < 0.);
|
|
}
|
|
|
|
if (theError)
|
|
*theError = anErr;
|
|
|
|
return false;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::IsHole(const TopoDS_Shape& aW, const TopoDS_Shape& aFace)
|
|
{
|
|
bool bIsHole;
|
|
int i, aNbS;
|
|
double aT1, aT2, aS;
|
|
double aU1, aU, dU;
|
|
double aX1, aY1, aX0, aY0;
|
|
TopAbs_Orientation aOr;
|
|
|
|
gp_Pnt2d aP2D0, aP2D1;
|
|
occ::handle<Geom2d_Curve> aC2D;
|
|
TopoDS_Face aF, aFF;
|
|
TopoDS_Iterator aItW;
|
|
//
|
|
bIsHole = false;
|
|
//
|
|
aF = (*(TopoDS_Face*)(&aFace));
|
|
aFF = aF;
|
|
aFF.Orientation(TopAbs_FORWARD);
|
|
//
|
|
aS = 0.;
|
|
aItW.Initialize(aW);
|
|
for (; aItW.More(); aItW.Next())
|
|
{
|
|
const TopoDS_Edge& aE = (*(TopoDS_Edge*)(&aItW.Value()));
|
|
aOr = aE.Orientation();
|
|
if (aOr != TopAbs_FORWARD && aOr != TopAbs_REVERSED)
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
aC2D = BRep_Tool::CurveOnSurface(aE, aFF, aT1, aT2);
|
|
if (aC2D.IsNull())
|
|
{
|
|
break; // xx
|
|
}
|
|
//
|
|
BRepAdaptor_Curve2d aBAC2D(aE, aFF);
|
|
aNbS = Geom2dInt_Geom2dCurveTool::NbSamples(aBAC2D);
|
|
if (aNbS > 2)
|
|
{
|
|
aNbS *= 4;
|
|
}
|
|
//
|
|
dU = (aT2 - aT1) / (double)(aNbS - 1);
|
|
aU = aT1;
|
|
aU1 = aT1;
|
|
if (aOr == TopAbs_REVERSED)
|
|
{
|
|
aU = aT2;
|
|
aU1 = aT2;
|
|
dU = -dU;
|
|
}
|
|
//
|
|
aBAC2D.D0(aU, aP2D0);
|
|
for (i = 2; i <= aNbS; i++)
|
|
{
|
|
aU = aU1 + (i - 1) * dU;
|
|
aBAC2D.D0(aU, aP2D1);
|
|
aP2D0.Coord(aX0, aY0);
|
|
aP2D1.Coord(aX1, aY1);
|
|
//
|
|
aS = aS + (aY0 + aY1) * (aX1 - aX0);
|
|
//
|
|
aP2D0 = aP2D1;
|
|
}
|
|
} // for (; aItW.More(); aItW.Next()) {
|
|
bIsHole = (aS > 0.);
|
|
return bIsHole;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void BOPTools_AlgoTools::MakeContainer(const TopAbs_ShapeEnum theType, TopoDS_Shape& theC)
|
|
{
|
|
BRep_Builder aBB;
|
|
//
|
|
switch (theType)
|
|
{
|
|
case TopAbs_COMPOUND: {
|
|
TopoDS_Compound aC;
|
|
aBB.MakeCompound(aC);
|
|
theC = aC;
|
|
}
|
|
break;
|
|
//
|
|
case TopAbs_COMPSOLID: {
|
|
TopoDS_CompSolid aCS;
|
|
aBB.MakeCompSolid(aCS);
|
|
theC = aCS;
|
|
}
|
|
break;
|
|
//
|
|
case TopAbs_SOLID: {
|
|
TopoDS_Solid aSolid;
|
|
aBB.MakeSolid(aSolid);
|
|
theC = aSolid;
|
|
}
|
|
break;
|
|
//
|
|
//
|
|
case TopAbs_SHELL: {
|
|
TopoDS_Shell aShell;
|
|
aBB.MakeShell(aShell);
|
|
theC = aShell;
|
|
}
|
|
break;
|
|
//
|
|
case TopAbs_WIRE: {
|
|
TopoDS_Wire aWire;
|
|
aBB.MakeWire(aWire);
|
|
theC = aWire;
|
|
}
|
|
break;
|
|
//
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void BOPTools_AlgoTools::MakePCurve(const TopoDS_Edge& aE,
|
|
const TopoDS_Face& aF1,
|
|
const TopoDS_Face& aF2,
|
|
const IntTools_Curve& aIC,
|
|
const bool bPC1,
|
|
const bool bPC2,
|
|
const occ::handle<IntTools_Context>& theContext)
|
|
|
|
{
|
|
int i;
|
|
double aTolE, aT1, aT2, aOutFirst, aOutLast, aOutTol;
|
|
occ::handle<Geom2d_Curve> aC2D, aC2DA, aC2Dx1;
|
|
TopoDS_Face aFFWD;
|
|
BRep_Builder aBB;
|
|
bool bPC;
|
|
//
|
|
aTolE = BRep_Tool::Tolerance(aE);
|
|
//
|
|
const occ::handle<Geom_Curve>& aC3DE = BRep_Tool::Curve(aE, aT1, aT2);
|
|
occ::handle<Geom_TrimmedCurve> aC3DETrim = new Geom_TrimmedCurve(aC3DE, aT1, aT2);
|
|
//
|
|
for (i = 0; i < 2; ++i)
|
|
{
|
|
bPC = !i ? bPC1 : bPC2;
|
|
if (!bPC)
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
if (!i)
|
|
{
|
|
aFFWD = aF1;
|
|
aC2Dx1 = aIC.FirstCurve2d();
|
|
}
|
|
else
|
|
{
|
|
aFFWD = aF2;
|
|
aC2Dx1 = aIC.SecondCurve2d();
|
|
}
|
|
//
|
|
aFFWD.Orientation(TopAbs_FORWARD);
|
|
//
|
|
aC2D = aC2Dx1;
|
|
if (aC2D.IsNull())
|
|
{
|
|
BOPTools_AlgoTools2D::BuildPCurveForEdgeOnFace(aE, aFFWD, theContext);
|
|
BOPTools_AlgoTools2D::CurveOnSurface(aE,
|
|
aFFWD,
|
|
aC2D,
|
|
aOutFirst,
|
|
aOutLast,
|
|
aOutTol,
|
|
theContext);
|
|
}
|
|
//
|
|
if (aC3DE->IsPeriodic())
|
|
{
|
|
BOPTools_AlgoTools2D::AdjustPCurveOnFace(aFFWD, aT1, aT2, aC2D, aC2DA, theContext);
|
|
}
|
|
else
|
|
{
|
|
BOPTools_AlgoTools2D::AdjustPCurveOnFace(aFFWD, aC3DETrim, aC2D, aC2DA, theContext);
|
|
}
|
|
//
|
|
aBB.UpdateEdge(aE, aC2DA, aFFWD, aTolE);
|
|
// BRepLib::SameParameter(aE);
|
|
}
|
|
BRepLib::SameParameter(aE);
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void BOPTools_AlgoTools::MakeEdge(const IntTools_Curve& theIC,
|
|
const TopoDS_Vertex& theV1,
|
|
const double theT1,
|
|
const TopoDS_Vertex& theV2,
|
|
const double theT2,
|
|
const double theTolR3D,
|
|
TopoDS_Edge& theE)
|
|
{
|
|
BRep_Builder aBB;
|
|
double aNeedTol = theTolR3D + BOPTools_AlgoTools::DTolerance();
|
|
//
|
|
aBB.UpdateVertex(theV1, aNeedTol);
|
|
aBB.UpdateVertex(theV2, aNeedTol);
|
|
//
|
|
BOPTools_AlgoTools::MakeSectEdge(theIC, theV1, theT1, theV2, theT2, theE);
|
|
//
|
|
aBB.UpdateEdge(theE, theTolR3D);
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
int BOPTools_AlgoTools::ComputeVV(const TopoDS_Vertex& aV1, const gp_Pnt& aP2, const double aTolP2)
|
|
{
|
|
double aTolV1, aTolSum, aTolSum2, aD2;
|
|
gp_Pnt aP1;
|
|
//
|
|
aTolV1 = BRep_Tool::Tolerance(aV1);
|
|
|
|
aTolSum = aTolV1 + aTolP2 + Precision::Confusion();
|
|
aTolSum2 = aTolSum * aTolSum;
|
|
//
|
|
aP1 = BRep_Tool::Pnt(aV1);
|
|
//
|
|
aD2 = aP1.SquareDistance(aP2);
|
|
if (aD2 > aTolSum2)
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
int BOPTools_AlgoTools::ComputeVV(const TopoDS_Vertex& aV1,
|
|
const TopoDS_Vertex& aV2,
|
|
const double aFuzz)
|
|
{
|
|
double aTolV1, aTolV2, aTolSum, aTolSum2, aD2;
|
|
gp_Pnt aP1, aP2;
|
|
double aFuzz1 = (aFuzz > Precision::Confusion() ? aFuzz : Precision::Confusion());
|
|
//
|
|
aTolV1 = BRep_Tool::Tolerance(aV1);
|
|
aTolV2 = BRep_Tool::Tolerance(aV2);
|
|
aTolSum = aTolV1 + aTolV2 + aFuzz1;
|
|
aTolSum2 = aTolSum * aTolSum;
|
|
//
|
|
aP1 = BRep_Tool::Pnt(aV1);
|
|
aP2 = BRep_Tool::Pnt(aV2);
|
|
//
|
|
aD2 = aP1.SquareDistance(aP2);
|
|
if (aD2 > aTolSum2)
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void BOPTools_AlgoTools::MakeVertex(const NCollection_List<TopoDS_Shape>& aLV, TopoDS_Vertex& aVnew)
|
|
{
|
|
int aNb = aLV.Extent();
|
|
if (aNb == 1)
|
|
aVnew = *((TopoDS_Vertex*)(&aLV.First()));
|
|
else if (aNb > 1)
|
|
{
|
|
double aNTol;
|
|
gp_Pnt aNC;
|
|
BRepLib::BoundingVertex(aLV, aNC, aNTol);
|
|
BRep_Builder aBB;
|
|
aBB.MakeVertex(aVnew, aNC, aNTol);
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::GetEdgeOnFace(const TopoDS_Edge& theE1,
|
|
const TopoDS_Face& theF2,
|
|
TopoDS_Edge& theE2)
|
|
{
|
|
bool bFound;
|
|
TopoDS_Iterator aItF, aItW;
|
|
//
|
|
bFound = false;
|
|
//
|
|
aItF.Initialize(theF2);
|
|
for (; aItF.More(); aItF.Next())
|
|
{
|
|
const TopoDS_Shape& aW = aItF.Value();
|
|
aItW.Initialize(aW);
|
|
for (; aItW.More(); aItW.Next())
|
|
{
|
|
const TopoDS_Shape& aE = aItW.Value();
|
|
if (aE.IsSame(theE1))
|
|
{
|
|
theE2 = (*(TopoDS_Edge*)(&aE));
|
|
bFound = !bFound;
|
|
return bFound;
|
|
}
|
|
}
|
|
}
|
|
return bFound;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool FindFacePairs(const TopoDS_Edge& theE,
|
|
const NCollection_List<TopoDS_Shape>& thLF,
|
|
NCollection_List<BOPTools_CoupleOfShape>& theLCFF,
|
|
const occ::handle<IntTools_Context>& theContext)
|
|
{
|
|
bool bFound;
|
|
int i, aNbCEF;
|
|
TopAbs_Orientation aOr, aOrC = TopAbs_FORWARD;
|
|
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aMFP;
|
|
TopoDS_Face aF1, aF2;
|
|
TopoDS_Edge aEL, aE1;
|
|
NCollection_List<TopoDS_Shape>::Iterator aItLF;
|
|
BOPTools_CoupleOfShape aCEF, aCFF;
|
|
NCollection_List<BOPTools_CoupleOfShape> aLCEF, aLCEFx;
|
|
NCollection_List<BOPTools_CoupleOfShape>::Iterator aIt;
|
|
//
|
|
bFound = true;
|
|
//
|
|
// Preface aLCEF
|
|
aItLF.Initialize(thLF);
|
|
for (; aItLF.More(); aItLF.Next())
|
|
{
|
|
const TopoDS_Face& aFL = (*(TopoDS_Face*)(&aItLF.Value()));
|
|
//
|
|
bFound = BOPTools_AlgoTools::GetEdgeOnFace(theE, aFL, aEL);
|
|
if (!bFound)
|
|
{
|
|
return bFound; // it can not be so
|
|
}
|
|
//
|
|
aCEF.SetShape1(aEL);
|
|
aCEF.SetShape2(aFL);
|
|
aLCEF.Append(aCEF);
|
|
}
|
|
//
|
|
aNbCEF = aLCEF.Extent();
|
|
while (aNbCEF)
|
|
{
|
|
//
|
|
// aLCEFx
|
|
aLCEFx.Clear();
|
|
aIt.Initialize(aLCEF);
|
|
for (i = 0; aIt.More(); aIt.Next(), ++i)
|
|
{
|
|
const BOPTools_CoupleOfShape& aCSx = aIt.Value();
|
|
const TopoDS_Shape& aEx = aCSx.Shape1();
|
|
const TopoDS_Shape& aFx = aCSx.Shape2();
|
|
//
|
|
aOr = aEx.Orientation();
|
|
//
|
|
if (!i)
|
|
{
|
|
aOrC = TopAbs::Reverse(aOr);
|
|
aE1 = (*(TopoDS_Edge*)(&aEx));
|
|
aF1 = (*(TopoDS_Face*)(&aFx));
|
|
aMFP.Add(aFx);
|
|
continue;
|
|
}
|
|
//
|
|
if (aOr == aOrC)
|
|
{
|
|
aLCEFx.Append(aCSx);
|
|
aMFP.Add(aFx);
|
|
}
|
|
}
|
|
//
|
|
// F2
|
|
BOPTools_AlgoTools::GetFaceOff(aE1, aF1, aLCEFx, aF2, theContext);
|
|
//
|
|
aCFF.SetShape1(aF1);
|
|
aCFF.SetShape2(aF2);
|
|
theLCFF.Append(aCFF);
|
|
//
|
|
aMFP.Add(aF1);
|
|
aMFP.Add(aF2);
|
|
//
|
|
// refine aLCEF
|
|
aLCEFx.Clear();
|
|
aLCEFx = aLCEF;
|
|
aLCEF.Clear();
|
|
aIt.Initialize(aLCEFx);
|
|
for (; aIt.More(); aIt.Next())
|
|
{
|
|
const BOPTools_CoupleOfShape& aCSx = aIt.Value();
|
|
const TopoDS_Shape& aFx = aCSx.Shape2();
|
|
if (!aMFP.Contains(aFx))
|
|
{
|
|
aLCEF.Append(aCSx);
|
|
}
|
|
}
|
|
//
|
|
aNbCEF = aLCEF.Extent();
|
|
} // while(aNbCEF) {
|
|
//
|
|
return bFound;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
double AngleWithRef(const gp_Dir& theD1, const gp_Dir& theD2, const gp_Dir& theDRef)
|
|
{
|
|
double aCosinus, aSinus, aBeta, aHalfPI, aScPr;
|
|
gp_XYZ aXYZ;
|
|
//
|
|
aHalfPI = 0.5 * M_PI;
|
|
//
|
|
const gp_XYZ& aXYZ1 = theD1.XYZ();
|
|
const gp_XYZ& aXYZ2 = theD2.XYZ();
|
|
aXYZ = aXYZ1.Crossed(aXYZ2);
|
|
aSinus = aXYZ.Modulus();
|
|
aCosinus = theD1 * theD2;
|
|
//
|
|
aBeta = 0.;
|
|
if (aSinus >= 0.)
|
|
{
|
|
aBeta = aHalfPI * (1. - aCosinus);
|
|
}
|
|
else
|
|
{
|
|
aBeta = 2. * M_PI - aHalfPI * (3. + aCosinus);
|
|
}
|
|
//
|
|
aScPr = aXYZ.Dot(theDRef.XYZ());
|
|
if (aScPr < 0.)
|
|
{
|
|
aBeta = -aBeta;
|
|
}
|
|
return aBeta;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::IsBlockInOnFace(const IntTools_Range& aShrR,
|
|
const TopoDS_Face& aF,
|
|
const TopoDS_Edge& aE1,
|
|
const occ::handle<IntTools_Context>& aContext)
|
|
{
|
|
bool bFlag;
|
|
double f1, l1, ULD, VLD;
|
|
gp_Pnt2d aP2D;
|
|
gp_Pnt aP11, aP12;
|
|
//
|
|
aShrR.Range(f1, l1);
|
|
double dt = 0.0075, k; // dt=0.001, k;
|
|
k = dt * (l1 - f1);
|
|
f1 = f1 + k;
|
|
l1 = l1 - k;
|
|
//
|
|
// Treatment P11
|
|
BOPTools_AlgoTools::PointOnEdge(aE1, f1, aP11);
|
|
//
|
|
GeomAPI_ProjectPointOnSurf& aProjector = aContext->ProjPS(aF);
|
|
aProjector.Perform(aP11);
|
|
//
|
|
bFlag = aProjector.IsDone();
|
|
if (!bFlag)
|
|
{
|
|
return bFlag;
|
|
}
|
|
|
|
aProjector.LowerDistanceParameters(ULD, VLD);
|
|
aP2D.SetCoord(ULD, VLD);
|
|
//
|
|
bFlag = aContext->IsPointInOnFace(aF, aP2D);
|
|
//
|
|
if (!bFlag)
|
|
{
|
|
return bFlag;
|
|
}
|
|
//
|
|
// Treatment P12
|
|
BOPTools_AlgoTools::PointOnEdge(aE1, l1, aP12);
|
|
//
|
|
aProjector.Perform(aP12);
|
|
//
|
|
bFlag = aProjector.IsDone();
|
|
if (!bFlag)
|
|
{
|
|
return bFlag;
|
|
}
|
|
|
|
aProjector.LowerDistanceParameters(ULD, VLD);
|
|
aP2D.SetCoord(ULD, VLD);
|
|
//
|
|
bFlag = aContext->IsPointInOnFace(aF, aP2D);
|
|
//
|
|
if (!bFlag)
|
|
{
|
|
return bFlag;
|
|
}
|
|
//
|
|
|
|
// Treatment intermediate
|
|
double m1, aTolF, aTolE, aTol, aDist;
|
|
m1 = IntTools_Tools::IntermediatePoint(f1, l1);
|
|
BOPTools_AlgoTools::PointOnEdge(aE1, m1, aP12);
|
|
//
|
|
aProjector.Perform(aP12);
|
|
//
|
|
bFlag = aProjector.IsDone();
|
|
if (!bFlag)
|
|
{
|
|
return bFlag;
|
|
}
|
|
//
|
|
aTolE = BRep_Tool::Tolerance(aE1);
|
|
aTolF = BRep_Tool::Tolerance(aF);
|
|
aTol = aTolE + aTolF;
|
|
aDist = aProjector.LowerDistance();
|
|
if (aDist > aTol)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
aProjector.LowerDistanceParameters(ULD, VLD);
|
|
aP2D.SetCoord(ULD, VLD);
|
|
//
|
|
bFlag = aContext->IsPointInOnFace(aF, aP2D);
|
|
//
|
|
if (!bFlag)
|
|
{
|
|
return bFlag;
|
|
}
|
|
return bFlag;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::IsMicroEdge(const TopoDS_Edge& aE,
|
|
const occ::handle<IntTools_Context>& aCtx,
|
|
const bool bCheckSplittable)
|
|
{
|
|
bool bRet;
|
|
double aT1, aT2, aTmp;
|
|
occ::handle<Geom_Curve> aC3D;
|
|
TopoDS_Vertex aV1, aV2;
|
|
//
|
|
bRet = (BRep_Tool::Degenerated(aE) || !BRep_Tool::IsGeometric(aE));
|
|
if (bRet)
|
|
{
|
|
return bRet;
|
|
}
|
|
//
|
|
aC3D = BRep_Tool::Curve(aE, aT1, aT2);
|
|
TopExp::Vertices(aE, aV1, aV2);
|
|
aT1 = BRep_Tool::Parameter(aV1, aE);
|
|
aT2 = BRep_Tool::Parameter(aV2, aE);
|
|
if (aT2 < aT1)
|
|
{
|
|
aTmp = aT1;
|
|
aT1 = aT2;
|
|
aT2 = aTmp;
|
|
}
|
|
//
|
|
IntTools_ShrunkRange aSR;
|
|
aSR.SetContext(aCtx);
|
|
aSR.SetData(aE, aT1, aT2, aV1, aV2);
|
|
aSR.Perform();
|
|
bRet = !aSR.IsDone();
|
|
if (!bRet && bCheckSplittable)
|
|
{
|
|
bRet = !aSR.IsSplittable();
|
|
}
|
|
//
|
|
return bRet;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : GetFaceDir
|
|
// purpose : Get binormal direction for the face in the point aP
|
|
//=======================================================================
|
|
bool GetFaceDir(const TopoDS_Edge& aE,
|
|
const TopoDS_Face& aF,
|
|
const gp_Pnt& aP,
|
|
const double aT,
|
|
const gp_Dir& aDTgt,
|
|
const bool theSmallFaces,
|
|
gp_Dir& aDN,
|
|
gp_Dir& aDB,
|
|
const occ::handle<IntTools_Context>& theContext,
|
|
GeomAPI_ProjectPointOnSurf& aProjPL,
|
|
const double aDt)
|
|
{
|
|
double aTolE;
|
|
gp_Pnt aPx;
|
|
//
|
|
BOPTools_AlgoTools3D::GetNormalToFaceOnEdge(aE, aF, aT, aDN, theContext);
|
|
if (aF.Orientation() == TopAbs_REVERSED)
|
|
{
|
|
aDN.Reverse();
|
|
}
|
|
//
|
|
aTolE = BRep_Tool::Tolerance(aE);
|
|
aDB = aDN ^ aDTgt;
|
|
//
|
|
// do not try to look for the point in the small face by intersecting
|
|
// it with the circle because, most likely, the intersection point will
|
|
// be out of the face
|
|
bool bFound =
|
|
!theSmallFaces && FindPointInFace(aF, aP, aDB, aPx, theContext, aProjPL, aDt, aTolE);
|
|
if (!bFound)
|
|
{
|
|
// if the first method did not succeed, try to use hatcher to find the point
|
|
bFound =
|
|
BOPTools_AlgoTools3D::GetApproxNormalToFaceOnEdge(aE, aF, aT, aDt, aPx, aDN, theContext);
|
|
aProjPL.Perform(aPx);
|
|
Standard_ASSERT_RETURN(aProjPL.IsDone(), "GetFaceDir: Project point on plane is failed", false);
|
|
aPx = aProjPL.NearestPoint();
|
|
gp_Vec aVec(aP, aPx);
|
|
aDB.SetXYZ(aVec.XYZ());
|
|
}
|
|
//
|
|
return bFound;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : FindPointInFace
|
|
// purpose : Find a point in the face in direction of <aDB>.
|
|
// To get this point the method intersects the circle with radius
|
|
// <aDt> built in point <aP> with normal perpendicular to <aDB>.
|
|
//=======================================================================
|
|
bool FindPointInFace(const TopoDS_Face& aF,
|
|
const gp_Pnt& aP,
|
|
gp_Dir& aDB,
|
|
gp_Pnt& aPOut,
|
|
const occ::handle<IntTools_Context>& theContext,
|
|
GeomAPI_ProjectPointOnSurf& aProjPL,
|
|
const double aDt,
|
|
const double aTolE)
|
|
{
|
|
int aNbItMax;
|
|
double aDist, aDTol, aPM, anEps;
|
|
bool bRet;
|
|
gp_Pnt aP1, aPS;
|
|
//
|
|
aDTol = Precision::Angular();
|
|
aPM = aP.XYZ().Modulus();
|
|
if (aPM > 1000.)
|
|
{
|
|
aDTol = 5.e-16 * aPM;
|
|
}
|
|
bRet = false;
|
|
aNbItMax = 15;
|
|
anEps = Precision::SquareConfusion();
|
|
//
|
|
GeomAPI_ProjectPointOnSurf& aProj = theContext->ProjPS(aF);
|
|
//
|
|
aPS = aP;
|
|
aProj.Perform(aPS);
|
|
if (!aProj.IsDone())
|
|
{
|
|
return bRet;
|
|
}
|
|
aPS = aProj.NearestPoint();
|
|
aProjPL.Perform(aPS);
|
|
aPS = aProjPL.NearestPoint();
|
|
//
|
|
aPS.SetXYZ(aPS.XYZ() + 2. * aTolE * aDB.XYZ());
|
|
aProj.Perform(aPS);
|
|
if (!aProj.IsDone())
|
|
{
|
|
return bRet;
|
|
}
|
|
aPS = aProj.NearestPoint();
|
|
aProjPL.Perform(aPS);
|
|
aPS = aProjPL.NearestPoint();
|
|
//
|
|
do
|
|
{
|
|
aP1.SetXYZ(aPS.XYZ() + aDt * aDB.XYZ());
|
|
//
|
|
aProj.Perform(aP1);
|
|
if (!aProj.IsDone())
|
|
{
|
|
return bRet;
|
|
}
|
|
aPOut = aProj.NearestPoint();
|
|
aDist = aProj.LowerDistance();
|
|
//
|
|
aProjPL.Perform(aPOut);
|
|
aPOut = aProjPL.NearestPoint();
|
|
//
|
|
gp_Vec aV(aPS, aPOut);
|
|
if (aV.SquareMagnitude() < anEps)
|
|
{
|
|
return bRet;
|
|
}
|
|
aDB.SetXYZ(aV.XYZ());
|
|
} while (aDist > aDTol && --aNbItMax);
|
|
//
|
|
bRet = aDist < aDTol;
|
|
return bRet;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
double MinStep3D(const TopoDS_Edge& theE1,
|
|
const TopoDS_Face& theF1,
|
|
const NCollection_List<BOPTools_CoupleOfShape>& theLCS,
|
|
const gp_Pnt& aP,
|
|
const occ::handle<IntTools_Context>& theContext,
|
|
bool& theSmallFaces)
|
|
{
|
|
double aDt, aTolE, aTolF, aDtMax, aDtMin;
|
|
//
|
|
// add the current pair of edge/face for checking as well
|
|
BOPTools_CoupleOfShape aCS1;
|
|
aCS1.SetShape1(theE1);
|
|
aCS1.SetShape2(theF1);
|
|
//
|
|
NCollection_List<BOPTools_CoupleOfShape> aLCS = theLCS;
|
|
aLCS.Append(aCS1);
|
|
//
|
|
aTolE = BRep_Tool::Tolerance(theE1);
|
|
aDtMax = -1.;
|
|
aDtMin = 5.e-6;
|
|
//
|
|
NCollection_List<BOPTools_CoupleOfShape>::Iterator aIt(aLCS);
|
|
for (; aIt.More(); aIt.Next())
|
|
{
|
|
const BOPTools_CoupleOfShape& aCS = aIt.Value();
|
|
const TopoDS_Face& aF = (*(TopoDS_Face*)(&aCS.Shape2()));
|
|
//
|
|
aTolF = BRep_Tool::Tolerance(aF);
|
|
aDt = 2 * (aTolE + aTolF);
|
|
if (aDt > aDtMax)
|
|
{
|
|
aDtMax = aDt;
|
|
}
|
|
//
|
|
// try to compute the minimal 3D step
|
|
const BRepAdaptor_Surface& aBAS = theContext->SurfaceAdaptor(aF);
|
|
double aR = 0.;
|
|
GeomAbs_SurfaceType aSType = aBAS.GetType();
|
|
switch (aSType)
|
|
{
|
|
case GeomAbs_Cylinder: {
|
|
aR = aBAS.Cylinder().Radius();
|
|
break;
|
|
}
|
|
case GeomAbs_Cone: {
|
|
gp_Lin aL(aBAS.Cone().Axis());
|
|
aR = aL.Distance(aP);
|
|
break;
|
|
}
|
|
case GeomAbs_Sphere: {
|
|
aDtMin = std::max(aDtMin, 5.e-4);
|
|
aR = aBAS.Sphere().Radius();
|
|
break;
|
|
}
|
|
case GeomAbs_Torus: {
|
|
aR = aBAS.Torus().MajorRadius();
|
|
break;
|
|
}
|
|
default:
|
|
aDtMin = std::max(aDtMin, 5.e-4);
|
|
break;
|
|
}
|
|
//
|
|
if (aR > 100.)
|
|
{
|
|
constexpr double d = 10 * Precision::PConfusion();
|
|
aDtMin = std::max(aDtMin, sqrt(d * d + 2 * d * aR));
|
|
}
|
|
}
|
|
//
|
|
if (aDtMax < aDtMin)
|
|
{
|
|
aDtMax = aDtMin;
|
|
}
|
|
//
|
|
// check if the computed 3D step is too big for any of the faces in the list
|
|
aIt.Initialize(aLCS);
|
|
for (; aIt.More(); aIt.Next())
|
|
{
|
|
const BOPTools_CoupleOfShape& aCS = aIt.Value();
|
|
const TopoDS_Face& aF = (*(TopoDS_Face*)(&aCS.Shape2()));
|
|
//
|
|
const BRepAdaptor_Surface& aBAS = theContext->SurfaceAdaptor(aF);
|
|
//
|
|
double aUMin, aUMax, aVMin, aVMax;
|
|
theContext->UVBounds(aF, aUMin, aUMax, aVMin, aVMax);
|
|
//
|
|
double aDU = aUMax - aUMin;
|
|
if (aDU > 0.)
|
|
{
|
|
double aURes = aBAS.UResolution(aDtMax);
|
|
if (2 * aURes > aDU)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
double aDV = aVMax - aVMin;
|
|
if (aDV > 0.)
|
|
{
|
|
double aVRes = aBAS.VResolution(aDtMax);
|
|
if (2 * aVRes > aDV)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
theSmallFaces = aIt.More();
|
|
//
|
|
return aDtMax;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::IsOpenShell(const TopoDS_Shell& aSh)
|
|
{
|
|
bool bRet;
|
|
int i, aNbE, aNbF;
|
|
TopAbs_Orientation aOrF;
|
|
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
|
|
aMEF;
|
|
NCollection_List<TopoDS_Shape>::Iterator aItLS;
|
|
//
|
|
bRet = false;
|
|
//
|
|
TopExp::MapShapesAndAncestors(aSh, TopAbs_EDGE, TopAbs_FACE, aMEF);
|
|
//
|
|
aNbE = aMEF.Extent();
|
|
for (i = 1; i <= aNbE; ++i)
|
|
{
|
|
const TopoDS_Edge& aE = *((TopoDS_Edge*)&aMEF.FindKey(i));
|
|
if (BRep_Tool::Degenerated(aE))
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
aNbF = 0;
|
|
const NCollection_List<TopoDS_Shape>& aLF = aMEF(i);
|
|
aItLS.Initialize(aLF);
|
|
for (; aItLS.More(); aItLS.Next())
|
|
{
|
|
const TopoDS_Shape& aF = aItLS.Value();
|
|
aOrF = aF.Orientation();
|
|
if (aOrF == TopAbs_INTERNAL || aOrF == TopAbs_EXTERNAL)
|
|
{
|
|
continue;
|
|
}
|
|
++aNbF;
|
|
}
|
|
//
|
|
if (aNbF == 1)
|
|
{
|
|
bRet = !bRet; // True
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
return bRet;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
bool BOPTools_AlgoTools::IsInvertedSolid(const TopoDS_Solid& aSolid)
|
|
{
|
|
double aTolS;
|
|
TopAbs_State aState;
|
|
BRepClass3d_SolidClassifier aSC(aSolid);
|
|
//
|
|
aTolS = 1.e-7;
|
|
aSC.PerformInfinitePoint(aTolS);
|
|
aState = aSC.State();
|
|
return (aState == TopAbs_IN);
|
|
}
|