Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
36c80dbe7This file is pinned to the selected release. Download the original to open it in your design tool.
// Created on: 2018-03-14
// Created by: Nikolai BUKHALOV
// Copyright (c) 1999-2018 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <BRepFill_AdvancedEvolved.hxx>
#include <BRep_Builder.hxx>
#include <BRepFill_PipeShell.hxx>
#include <BRepFill_TransitionStyle.hxx>
#include <TopTools_ListOfShape.hxx>
#include <BOPAlgo_Tools.hxx>
#include <BRepLib_FindSurface.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BOPAlgo_MakerVolume.hxx>
#include <BOPAlgo_PaveFiller.hxx>
#include <Adaptor3d_Surface.hxx>
#include <math_NewtonMinimum.hxx>
#include <BOPTools_AlgoTools.hxx>
#include <math_Vector.hxx>
#include <BRepTools_WireExplorer.hxx>
#include <BRepTools.hxx>
#include <BOPAlgo_BuilderFace.hxx>
#include <Geom2d_Line.hxx>
#include <math_GlobOptMin.hxx>
#include <Extrema_ExtPC.hxx>
#include <BOPDS_DS.hxx>
#include <BRepLib.hxx>
#include <BRepExtrema_DistShapeShape.hxx>
#include <BRepLib_MakeFace.hxx>
#include <ShapeFix_Shape.hxx>
#include <BRepClass_FaceClassifier.hxx>
#include <BRepGProp_Face.hxx>
#include <BRep_TEdge.hxx>
#include <ShapeUpgrade_UnifySameDomain.hxx>
#include <Bnd_Box.hxx>
#include <BRepBndLib.hxx>
#ifdef BRepFill_AdvancedEvolved_DEBUG
#include <BinTools.hxx>
#endif
static const Standard_Real aPipeLinearTolerance = 1.0e-4;
static const Standard_Real aPipeAngularTolerance = 1.0e-2;
static Standard_Boolean ContainsInList(const TopTools_ListOfShape& theL,
const TopoDS_Shape& theObject);
static void FindInternals(const TopoDS_Shape& theS, TopTools_ListOfShape& theLInt);
static void RemoveInternalWires(const TopoDS_Shape& theShape);
static void ProcessVertex(const TopoDS_Vertex& aV,
const TopTools_ListOfShape& aLE,
const TopTools_ListOfShape& aLF);
static void ReduceVertexTolerance(const TopoDS_Shape& aS);
//=================================================================================================
Standard_Boolean BRepFill_AdvancedEvolved::PerformBoolean(const TopTools_ListOfShape& theArgsList,
TopoDS_Shape& theResult) const
{
BOPAlgo_PaveFiller aPF;
aPF.SetArguments(theArgsList);
aPF.SetRunParallel(myIsParallel);
aPF.SetFuzzyValue(myFuzzyValue);
aPF.Perform();
if (aPF.HasErrors())
{
return Standard_False;
}
BOPAlgo_Builder aBuilder;
aBuilder.SetArguments(theArgsList);
aBuilder.SetRunParallel(myIsParallel);
aBuilder.PerformWithFiller(aPF);
if (aBuilder.HasErrors())
{
return Standard_False;
}
theResult = aBuilder.Shape();
return Standard_True;
}
//=================================================================================================
void BRepFill_AdvancedEvolved::GetSpineAndProfile(const TopoDS_Wire& theSpine,
const TopoDS_Wire& theProfile)
{
mySpine = theSpine;
myProfile = theProfile;
TopTools_IndexedDataMapOfShapeListOfShape aMVEP;
TopExp::MapShapesAndAncestors(theProfile, TopAbs_VERTEX, TopAbs_EDGE, aMVEP);
gp_Vec aN2;
gp_Pnt aLoc;
for (Standard_Integer i = 1; i <= aMVEP.Size(); i++)
{
const TopoDS_Vertex& aVC = TopoDS::Vertex(aMVEP.FindKey(i));
const TopTools_ListOfShape& aLE = aMVEP.FindFromIndex(i);
if (aLE.Extent() < 2)
continue;
const TopoDS_Edge& anE1 = TopoDS::Edge(aLE.First());
const TopoDS_Edge& anE2 = TopoDS::Edge(aLE.Last());
const BRepAdaptor_Curve anAC1(anE1), anAC2(anE2);
const Standard_Real aPar1 = BRep_Tool::Parameter(aVC, anE1);
const Standard_Real aPar2 = BRep_Tool::Parameter(aVC, anE2);
gp_Pnt aP;
gp_Vec aT1, aT2;
anAC1.D1(aPar1, aP, aT1);
anAC1.D1(aPar2, aP, aT2);
aN2 = aT1.Crossed(aT2);
if (aN2.SquareMagnitude() > Precision::SquareConfusion())
{
aLoc = BRep_Tool::Pnt(aVC);
break;
}
}
BRepExtrema_DistShapeShape anExtr;
anExtr.LoadS1(theSpine);
if (aN2.SquareMagnitude() > Precision::SquareConfusion())
{
const gp_Pln aPln(aLoc, aN2);
BRepLib_MakeFace aMF(aPln, theProfile);
if (!aMF.IsDone())
return;
anExtr.LoadS2(aMF.Face());
}
else
{
anExtr.LoadS2(theProfile);
}
if (!anExtr.Perform())
return;
const Standard_Integer aNbSol = anExtr.NbSolution();
if (aNbSol < 1)
return;
Standard_Real aDistMin = RealLast();
Standard_Integer anIdxMin = 0;
for (Standard_Integer aSolId = 1; aSolId <= aNbSol; aSolId++)
{
const Standard_Real aD = anExtr.Value();
if (aD > aDistMin)
continue;
aDistMin = aD;
anIdxMin = aSolId;
}
BRepExtrema_SupportType anExtrType2 = anExtr.SupportTypeShape2(anIdxMin);
if (aDistMin < Precision::Confusion())
{
anExtrType2 = BRepExtrema_IsInFace;
}
switch (anExtrType2)
{
case BRepExtrema_IsInFace:
if (anExtr.SupportTypeShape1(anIdxMin) == BRepExtrema_IsVertex)
{
const TopoDS_Vertex aV = TopoDS::Vertex(anExtr.SupportOnShape1(anIdxMin));
TopTools_IndexedDataMapOfShapeListOfShape aMVES;
TopExp::MapShapesAndAncestors(theSpine, TopAbs_VERTEX, TopAbs_EDGE, aMVES);
const TopTools_ListOfShape& aLE = aMVES.FindFromKey(aV);
const TopoDS_Edge& anE1 = TopoDS::Edge(aLE.First());
const TopoDS_Edge& anE2 = TopoDS::Edge(aLE.Last());
const BRepAdaptor_Curve anAC1(anE1), anAC2(anE2);
const Standard_Real aPar1 = BRep_Tool::Parameter(aV, anE1);
const Standard_Real aPar2 = BRep_Tool::Parameter(aV, anE2);
gp_Pnt aP;
gp_Vec aT1, aT2;
anAC1.D1(aPar1, aP, aT1);
anAC1.D1(aPar2, aP, aT2);
// Find minimal sine
const Standard_Real aSqT1 = Max(aT1.SquareMagnitude(), 1.0 / Precision::Infinite());
const Standard_Real aSqT2 = Max(aT2.SquareMagnitude(), 1.0 / Precision::Infinite());
const Standard_Real aSqSin1 = aT1.CrossSquareMagnitude(aN2) / aSqT1;
const Standard_Real aSqSin2 = aT2.CrossSquareMagnitude(aN2) / aSqT2;
if (aSqSin1 < aSqSin2)
{
if (aT1.Dot(aN2) > 0.0)
{
myProfile.Reverse();
}
}
else
{
if (aT2.Dot(aN2) > 0.0)
{
myProfile.Reverse();
}
}
}
else // if (... == BRepExtrema_IsOnEdge)
{
const TopoDS_Edge anE = TopoDS::Edge(anExtr.SupportOnShape1(anIdxMin));
const BRepAdaptor_Curve anAC(anE);
Standard_Real aPar;
anExtr.ParOnEdgeS1(anIdxMin, aPar);
gp_Pnt aP;
gp_Vec aT1;
anAC.D1(aPar, aP, aT1);
if (aT1.Dot(aN2) > 0.0)
{
myProfile.Reverse();
}
}
break;
case BRepExtrema_IsOnEdge:
case BRepExtrema_IsVertex: {
const BRepLib_MakeFace aMkFSpine(theSpine, Standard_True);
if (!aMkFSpine.IsDone())
return;
const TopoDS_Face& aFSpine = aMkFSpine.Face();
const Handle(Geom_Plane) aPlnSpine =
Handle(Geom_Plane)::DownCast(BRep_Tool::Surface(aFSpine));
const gp_Vec aN1(aPlnSpine->Axis().Direction());
gp_Vec aTanV;
if (anExtr.SupportTypeShape2(anIdxMin) == BRepExtrema_IsVertex)
{
const TopoDS_Vertex aV = TopoDS::Vertex(anExtr.SupportOnShape2(anIdxMin));
TopTools_IndexedDataMapOfShapeListOfShape aMVES;
TopExp::MapShapesAndAncestors(theProfile, TopAbs_VERTEX, TopAbs_EDGE, aMVES);
const TopTools_ListOfShape& aLE = aMVES.FindFromKey(aV);
const TopoDS_Edge& anE1 = TopoDS::Edge(aLE.First());
const TopoDS_Edge& anE2 = TopoDS::Edge(aLE.Last());
const BRepAdaptor_Curve anAC1(anE1), anAC2(anE2);
const Standard_Real aPar1 = BRep_Tool::Parameter(aV, anE1);
const Standard_Real aPar2 = BRep_Tool::Parameter(aV, anE2);
gp_Pnt aP;
gp_Vec aT1, aT2;
anAC1.D1(aPar1, aP, aT1);
anAC1.D1(aPar2, aP, aT2);
// Find maximal cosine
Standard_Real aSqT1 = aT1.SquareMagnitude();
Standard_Real aSqT2 = aT2.SquareMagnitude();
if (aSqT1 < Precision::SquareConfusion())
aSqT1 = RealLast();
if (aSqT2 < Precision::SquareConfusion())
aSqT2 = RealLast();
const Standard_Real aDP1 = aT1.Dot(aN1);
const Standard_Real aDP2 = aT2.Dot(aN1);
if (aDP1 * aDP1 * aSqT2 > aDP2 * aDP2 * aSqT1)
{
// aDP1*aDP1/aSqT1 > aDP2*aDP2/aSqT2
aTanV = aT1;
}
else
{
aTanV = aT2;
}
}
else // if(anExtr.SupportTypeShape2(anIdxMin) == BRepExtrema_IsOnEdge)
{
const TopoDS_Edge anE = TopoDS::Edge(anExtr.SupportOnShape2(anIdxMin));
const BRepAdaptor_Curve anAC(anE);
Standard_Real aPar;
anExtr.ParOnEdgeS2(anIdxMin, aPar);
gp_Pnt aP;
anAC.D1(aPar, aP, aTanV);
}
// The point in the profile, which is the nearest to the spine
const gp_Pnt& aPnear = anExtr.PointOnShape2(anIdxMin);
BRepClass_FaceClassifier aFClass(aFSpine, aPnear, Precision::Confusion());
if (aFClass.State() != TopAbs_OUT)
{
if (aN1.Dot(aTanV) < 0.0)
{
myProfile.Reverse();
}
}
else
{
if (aN1.Dot(aTanV) > 0.0)
{
myProfile.Reverse();
}
}
}
break;
default:
break;
}
}
//=================================================================================================
Standard_Boolean BRepFill_AdvancedEvolved::IsLid(
const TopoDS_Face& theF,
const TopTools_IndexedMapOfShape& theMapOfLids) const
{
if (theMapOfLids.IsEmpty())
return Standard_False;
const Handle(Geom_Plane) aPlnF = Handle(Geom_Plane)::DownCast(BRep_Tool::Surface(theF));
if (aPlnF.IsNull())
return Standard_False;
TopTools_IndexedMapOfShape::Iterator anItr(theMapOfLids);
for (; anItr.More(); anItr.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anItr.Value());
const Handle(Geom_Plane) aPlane = Handle(Geom_Plane)::DownCast(BRep_Tool::Surface(aF));
if (aPlane == aPlnF)
return Standard_True;
}
return Standard_False;
}
//=================================================================================================
void BRepFill_AdvancedEvolved::Perform(const TopoDS_Wire& theSpine,
const TopoDS_Wire& theProfile,
const Standard_Real theTolerance,
const Standard_Boolean theSolidReq)
{
myErrorStatus = BRepFill_AdvancedEvolved_Empty;
if (myFuzzyValue < Precision::Confusion())
{
myFuzzyValue = theTolerance;
}
#ifdef BRepFill_AdvancedEvolved_DEBUG
char aBuff[10000];
Sprintf(aBuff, "%s%s", myDebugShapesPath, "spine.nbv");
BinTools::Write(theSpine, aBuff);
Sprintf(aBuff, "%s%s", myDebugShapesPath, "profile.nbv");
BinTools::Write(theProfile, aBuff);
std::streamsize aPrecVal = std::cout.precision();
std::cout.precision(15);
std::cout << "++++ Dump of Spine" << std::endl;
BRepTools::Dump(theSpine, std::cout);
std::cout << "---- Dump of Spine" << std::endl;
std::cout << "++++ Dump of Profile" << std::endl;
BRepTools::Dump(theProfile, std::cout);
std::cout << "---- Dump of Profile" << std::endl;
std::cout.precision(aPrecVal);
#endif
GetSpineAndProfile(theSpine, theProfile);
myPipeShell.Nullify();
myTopBottom.Nullify();
myResult.Nullify();
#ifdef BRepFill_AdvancedEvolved_DEBUG
std::cout << "Start Evolved. Toler = " << myFuzzyValue << std::endl;
#endif
PerformSweep();
#ifdef BRepFill_AdvancedEvolved_DEBUG
std::cout << "PerformSweep complete. Status = " << myErrorStatus << std::endl;
#endif
GetLids();
#ifdef BRepFill_AdvancedEvolved_DEBUG
std::cout << "GetLids complete. Status = " << myErrorStatus << std::endl;
#endif
if (myErrorStatus != BRepFill_AdvancedEvolved_NotSolid)
{
return;
}
myResult = myPipeShell;
BuildSolid();
if ((myErrorStatus != BRepFill_AdvancedEvolved_OK) || theSolidReq)
{
return;
}
TopoDS_Shell aShell;
TopTools_IndexedMapOfShape aMFLids;
TopExp::MapShapes(myTopBottom, TopAbs_FACE, aMFLids);
TopExp_Explorer anExp(myResult, TopAbs_FACE);
for (; anExp.More(); anExp.Next())
{
BRep_Builder aBB;
if (aShell.IsNull())
aBB.MakeShell(aShell);
const TopoDS_Face& aF = TopoDS::Face(anExp.Current());
if (IsLid(aF, aMFLids))
continue;
aBB.Add(aShell, aF);
}
if (!aShell.IsNull())
myResult = aShell;
}
//=================================================================================================
void BRepFill_AdvancedEvolved::PerformSweep()
{
if (myErrorStatus != BRepFill_AdvancedEvolved_Empty)
return;
myErrorStatus = BRepFill_AdvancedEvolved_SweepError;
Handle(BRepFill_PipeShell) aPipe = new BRepFill_PipeShell(mySpine);
aPipe->SetTolerance(aPipeLinearTolerance, aPipeLinearTolerance, aPipeAngularTolerance);
aPipe->SetTransition(BRepFill_Round);
aPipe->Add(myProfile, Standard_False, Standard_False);
if (aPipe->Build())
{
myErrorStatus = BRepFill_AdvancedEvolved_NoLids;
myPipeShell = aPipe->Shape();
}
}
//=================================================================================================
void BRepFill_AdvancedEvolved::GetLids()
{
if (myPipeShell.IsNull())
return;
if (BRep_Tool::IsClosed(myProfile))
{
// No need in lids creation
myErrorStatus = BRepFill_AdvancedEvolved_NotSolid;
return;
}
myErrorStatus = BRepFill_AdvancedEvolved_NoLids;
BRepLib_FindSurface aFS(mySpine, -1.0, Standard_True);
const Handle(Geom_Plane) aSurf = Handle(Geom_Plane)::DownCast(aFS.Surface());
if (aSurf.IsNull())
{
myErrorStatus = BRepFill_AdvancedEvolved_NotPlanarSpine;
return;
}
Standard_Real aTol = Max(aFS.Tolerance(), aFS.ToleranceReached());
aTol += myFuzzyValue;
Bnd_Box aProfBox;
BRepBndLib::Add(myProfile, aProfBox);
Standard_Real aSqDiag = aProfBox.SquareExtent();
// Square of the default angular tolerance in
// BOPAlgo_Tools::EdgesToWires(...) and BOPAlgo_Tools::WiresToFaces(...) methods
const Standard_Real aSqAnguarTol = aTol * aTol / aSqDiag;
const gp_Dir& aNormal = aSurf->Position().Direction();
// Obtain free-edges from myPipeShell. All edges must be planar
// and parallel to the plane of mySpine
TopTools_IndexedDataMapOfShapeListOfShape aMapEF;
TopExp::MapShapesAndAncestors(myPipeShell, TopAbs_EDGE, TopAbs_FACE, aMapEF);
TopTools_ListOfShape aLE;
gp_Pnt aPtmp;
gp_Vec aTan;
Standard_Real aDPMax = 0.;
for (Standard_Integer i = 1; i <= aMapEF.Size(); i++)
{
TopTools_ListOfShape& aListF = aMapEF(i);
if (aListF.Extent() != 1)
continue;
const TopoDS_Edge& anE = TopoDS::Edge(aMapEF.FindKey(i));
BRepAdaptor_Curve anAC(anE);
if (!anAC.Is3DCurve())
{
// We are not interested in degenerated edges.
continue;
}
anAC.D1(0.5 * (anAC.FirstParameter() + anAC.LastParameter()), aPtmp, aTan);
const Standard_Real aSqModulus = aTan.SquareMagnitude();
if (aSqModulus < Precision::Confusion())
continue;
const Standard_Real aDP = aTan.XYZ().Dot(aNormal.XYZ());
if (Abs(aDP) > aDPMax)
aDPMax = Abs(aDP);
if (aDP * aDP > aSqModulus * aSqAnguarTol)
{
// Only planar edges are considered
continue;
}
aLE.Append(anE);
}
if (aLE.IsEmpty())
{
myErrorStatus = BRepFill_AdvancedEvolved_NotPlanarSpine;
return;
}
// Split interfered edges
TopoDS_Shape aFreeEdges;
if (!PerformBoolean(aLE, aFreeEdges))
{
myErrorStatus = BRepFill_AdvancedEvolved_NotPlanarSpine;
return;
}
// Collect all free edges to wires and create planar
// top and bottom lids from these wires.
BRep_Builder aBB;
TopoDS_Compound aCompW, aCompF;
aBB.MakeCompound(aCompW);
aBB.MakeCompound(aCompF);
aBB.MakeCompound(myTopBottom);
Standard_Real anAngTol = Sqrt(aSqAnguarTol);
BOPAlgo_Tools::EdgesToWires(aFreeEdges, aCompW, Standard_True, anAngTol);
BOPAlgo_Tools::WiresToFaces(aCompW, aCompF, anAngTol);
{
// Check orientation
TopTools_IndexedMapOfShape aMapV;
TopExp::MapShapes(myPipeShell, TopAbs_VERTEX, aMapV);
TopExp_Explorer anExp(aCompF, TopAbs_FACE);
for (; anExp.More(); anExp.Next())
{
const TopoDS_Face aF = TopoDS::Face(anExp.Current());
const Handle(Geom_Plane) aPln = Handle(Geom_Plane)::DownCast(BRep_Tool::Surface(aF));
const gp_XYZ& aNorm = aPln->Position().Direction().XYZ();
const gp_XYZ& aLocP = aPln->Position().Location().XYZ();
Standard_Boolean isFound = Standard_False;
for (Standard_Integer i = 1; i <= aMapV.Size(); i++)
{
const TopoDS_Vertex aV = TopoDS::Vertex(aMapV.FindKey(i));
const gp_XYZ aP = BRep_Tool::Pnt(aV).XYZ();
const gp_XYZ aDelta = aP - aLocP;
const Standard_Real aSqD = aDelta.SquareModulus();
if (aSqD < Precision::SquareConfusion())
continue;
const Standard_Real aDP = aDelta.Dot(aNorm);
if (aDP * aDP < aSqD * Precision::SquareConfusion())
{
// aP is in the plane
continue;
}
if (aDP > 0.0)
{
aBB.Add(myTopBottom, aF.Reversed());
}
else
{
aBB.Add(myTopBottom, aF);
}
isFound = Standard_True;
break;
}
if (!isFound)
{
aBB.Add(myTopBottom, aF);
}
}
}
myErrorStatus = BRepFill_AdvancedEvolved_NotSolid;
}
//=================================================================================================
void BRepFill_AdvancedEvolved::BuildSolid()
{
if (myErrorStatus != BRepFill_AdvancedEvolved_NotSolid)
return;
myErrorStatus = BRepFill_AdvancedEvolved_NotVolume;
TopTools_MapOfShape aMapF;
TopTools_ListOfShape aLF, aLSplits;
TopExp_Explorer anExpF;
#ifdef BRepFill_AdvancedEvolved_DEBUG
char aBuff[10000];
Sprintf(aBuff, "%s%s", myDebugShapesPath, "shape2.nbv");
BinTools::Write(myPipeShell, aBuff);
#endif
for (anExpF.Init(myPipeShell, TopAbs_FACE); anExpF.More(); anExpF.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anExpF.Current());
if (!aMapF.Add(aF))
continue;
ReduceVertexTolerance(aF);
CheckSingularityAndAdd(aF, myFuzzyValue, aLF, aLSplits);
}
{
TopTools_ListIteratorOfListOfShape anItrS(aLSplits);
for (; anItrS.More(); anItrS.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anItrS.Value());
aLF.Append(aF);
}
#ifdef BRepFill_AdvancedEvolved_DEBUG
BRep_Builder aBB;
TopoDS_Compound aDebComp;
aBB.MakeCompound(aDebComp);
TopTools_ListIteratorOfListOfShape anItrDeb(aLF);
for (; anItrDeb.More(); anItrDeb.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anItrDeb.Value());
aBB.Add(aDebComp, aF);
}
Sprintf(aBuff, "%s%s", myDebugShapesPath, "shape3.nbv");
BinTools::Write(aDebComp, aBuff);
#endif
// Split interfered faces
PerformBoolean(aLF, myPipeShell);
#ifdef BRepFill_AdvancedEvolved_DEBUG
Sprintf(aBuff, "%s%s", myDebugShapesPath, "shape4.nbv");
BinTools::Write(myPipeShell, aBuff);
#endif
}
aLF.Clear();
aMapF.Clear();
for (anExpF.Init(myPipeShell, TopAbs_FACE); anExpF.More(); anExpF.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anExpF.Current());
if (!aMapF.Add(aF))
continue;
aLF.Append(aF);
}
if (!myTopBottom.IsNull())
{
TopoDS_Iterator anItLids(myTopBottom);
for (; anItLids.More(); anItLids.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anItLids.Value());
aLF.Append(aF);
}
}
#ifdef BRepFill_AdvancedEvolved_DEBUG
BRep_Builder aBB;
TopoDS_Compound aDebComp;
aBB.MakeCompound(aDebComp);
TopTools_ListIteratorOfListOfShape anItrDeb(aLF);
for (; anItrDeb.More(); anItrDeb.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anItrDeb.Value());
aBB.Add(aDebComp, aF);
}
Sprintf(aBuff, "%s%s", myDebugShapesPath, "shape5.nbv");
BinTools::Write(aDebComp, aBuff);
#endif
BOPAlgo_MakerVolume aMV;
aMV.SetArguments(aLF);
aMV.SetFuzzyValue(myFuzzyValue);
aMV.SetIntersect(Standard_True);
aMV.SetRunParallel(myIsParallel);
aMV.SetAvoidInternalShapes(Standard_True);
aMV.Perform();
if (aMV.HasErrors())
{
return;
}
myResult = aMV.Shape();
#ifdef BRepFill_AdvancedEvolved_DEBUG
std::cout << "BuildSolid After VM." << std::endl;
#endif
RemoveExcessSolids(aLSplits, myResult, aLF, aMV);
UnifyShape();
RemoveInternalWires(myResult);
myErrorStatus = BRepFill_AdvancedEvolved_OK;
}
//=================================================================================================
void BRepFill_AdvancedEvolved::UnifyShape()
{
ShapeUpgrade_UnifySameDomain aUnifier;
aUnifier.Initialize(myResult, Standard_True, Standard_True, Standard_False);
aUnifier.SetSafeInputMode(Standard_True);
aUnifier.AllowInternalEdges(Standard_False);
aUnifier.SetLinearTolerance(aPipeLinearTolerance);
aUnifier.SetAngularTolerance(aPipeAngularTolerance);
aUnifier.Build();
myResult = aUnifier.Shape();
}
//=================================================================================================
void BRepFill_AdvancedEvolved::ExtractOuterSolid(TopoDS_Shape& theShape,
TopTools_ListOfShape& theArgsList)
{
TopTools_IndexedDataMapOfShapeListOfShape aMapS;
TopExp::MapShapesAndAncestors(theShape, TopAbs_FACE, TopAbs_SOLID, aMapS);
// theArgsList.Clear();
TopTools_ListOfShape aNewList;
const Standard_Integer aNbF = aMapS.Extent();
for (Standard_Integer i = 1; i <= aNbF; ++i)
{
if (aMapS(i).Extent() == 1)
aNewList.Append(aMapS.FindKey(i));
}
if (aNewList.IsEmpty())
return;
{
TopTools_ListIteratorOfListOfShape anItrF;
Standard_Boolean isRemoved = Standard_True;
while (isRemoved)
{
isRemoved = Standard_False;
for (anItrF.Init(theArgsList); anItrF.More(); anItrF.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anItrF.Value());
if (!ContainsInList(aNewList, aF))
{
theArgsList.Remove(aF);
isRemoved = Standard_True;
break;
}
}
}
}
BOPAlgo_MakerVolume aMV;
aMV.SetArguments(aNewList);
aMV.SetIntersect(Standard_True);
aMV.SetRunParallel(myIsParallel);
aMV.SetAvoidInternalShapes(Standard_True);
aMV.Perform();
if (aMV.HasErrors())
{
return;
}
theShape = aMV.Shape();
}
//=================================================================================================
void BRepFill_AdvancedEvolved::RemoveExcessSolids(const TopTools_ListOfShape& theLSplits,
const TopoDS_Shape& theShape,
TopTools_ListOfShape& theArgsList,
BOPAlgo_MakerVolume& theMV)
{
if (myErrorStatus != BRepFill_AdvancedEvolved_NotVolume)
return;
TopoDS_Shape aResShape = theShape;
TopExp_Explorer anExpSo;
for (Standard_Integer i = 0; i < 2; i++)
{
anExpSo.Init(aResShape, TopAbs_SOLID);
if (!anExpSo.More())
{
// No any solids
myResult = aResShape;
return;
}
anExpSo.Next();
if (!anExpSo.More())
{
// Only one solid has been generated
myResult = TopoDS::Solid(anExpSo.Current());
return;
}
if (i != 0)
break;
ExtractOuterSolid(aResShape, theArgsList);
}
TopTools_ListOfShape aSolidList;
// Look for all solids containing lids
{
anExpSo.Init(aResShape, TopAbs_SOLID);
for (; anExpSo.More(); anExpSo.Next())
{
const TopoDS_Solid& aSol = TopoDS::Solid(anExpSo.Current());
TopTools_IndexedMapOfShape aMapF;
TopExp::MapShapes(aSol, aMapF);
Standard_Boolean areThereLids = Standard_False;
TopExp_Explorer anExpLids(myTopBottom, TopAbs_FACE);
for (; anExpLids.More(); anExpLids.Next())
{
areThereLids = Standard_True;
const TopoDS_Face& aFLid = TopoDS::Face(anExpLids.Current());
const Standard_Integer aFIdx = aMapF.FindIndex(aFLid);
if (aFIdx < 1)
continue;
const TopoDS_Face& aFSol = TopoDS::Face(aMapF.FindKey(aFIdx));
if (aFSol.IsEqual(aFLid))
{
aSolidList.Append(aSol);
}
break;
}
if (!areThereLids)
break;
}
if (aSolidList.Extent() < 1)
{
myResult = aResShape;
return;
}
if (aSolidList.Extent() == 1)
{
myResult = aSolidList.First();
return;
}
if (aSolidList.Extent() > 0)
{
BRep_Builder aBB;
TopoDS_CompSolid aCompSol;
aBB.MakeCompSolid(aCompSol);
TopTools_ListIteratorOfListOfShape anItl(aSolidList);
for (; anItl.More(); anItl.Next())
{
const TopoDS_Solid& aSol = TopoDS::Solid(anItl.Value());
aBB.Add(aCompSol, aSol);
}
aResShape = aCompSol;
aSolidList.Clear();
}
}
{
// Remove Split faces from the list of arguments
TopTools_ListIteratorOfListOfShape anItl(theLSplits);
for (; anItl.More(); anItl.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anItl.Value());
theArgsList.Remove(aF);
}
// Create a list of invalid faces. The face is invalid if
// BOPAlgo_MakerVolume changes its orientation while creating solids.
// Faces from theLSplits are not checked.
TopTools_ListOfShape aListInvFaces;
for (anItl.Init(theArgsList); anItl.More(); anItl.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anItl.Value());
for (TopTools_ListIteratorOfListOfShape anItM(theMV.Modified(aF)); anItM.More(); anItM.Next())
{
const TopoDS_Face& aFM = TopoDS::Face(anItM.Value());
if (aFM.Orientation() != aF.Orientation())
aListInvFaces.Append(aFM);
}
}
for (anExpSo.Init(aResShape, TopAbs_SOLID); anExpSo.More(); anExpSo.Next())
{
const TopoDS_Solid& aSo = TopoDS::Solid(anExpSo.Current());
TopTools_IndexedMapOfShape aMapF;
TopExp::MapShapes(aSo, TopAbs_FACE, aMapF);
Standard_Boolean isToDelete = Standard_False;
for (anItl.Init(aListInvFaces); anItl.More(); anItl.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anItl.Value());
if (aMapF.Contains(aF))
{
isToDelete = Standard_True;
break;
}
}
if (isToDelete)
{
continue;
}
for (anItl.Init(theArgsList); anItl.More(); anItl.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anItl.Value());
const Standard_Integer anIdx = aMapF.FindIndex(aF);
if (anIdx == 0)
continue;
const TopoDS_Face& aF1 = TopoDS::Face(aMapF.FindKey(anIdx));
// aF and aF1 are same shapes. Check if they are equal.
if (!aF.IsEqual(aF1))
{
isToDelete = Standard_True;
break;
}
}
if (isToDelete)
{
continue;
}
aSolidList.Append(aSo);
}
}
if (aSolidList.Extent() < 1)
{
myResult = aResShape;
return;
}
if (aSolidList.Extent() == 1)
{
myResult = aSolidList.First();
return;
}
BRep_Builder aBB;
TopoDS_CompSolid aCmpSol;
aBB.MakeCompSolid(aCmpSol);
for (TopTools_ListIteratorOfListOfShape anItl(aSolidList); anItl.More(); anItl.Next())
{
const TopoDS_Solid& aSo = TopoDS::Solid(anItl.Value());
aBB.Add(aCmpSol, aSo);
}
myResult = aCmpSol;
}
#if 0
//=======================================================================
//class : NormalFunc
//purpose : This function computes square modulus of the normal to the
// surface in every point of the curve myCOnS. It allows detecting
// whether the curve goes through the singular point(s).
// It will be useful in case(s) when the result after PipeShell
// algorithm contains only one face with single seam-edge. E.g.:
// Draw[]> ellipse cc 0 0 0 0 0 1 30 10
// Draw[]> mkedge ee cc
// Draw[]> wire ww ee
// Draw[]> polyline tw 0 25 -5 0 -20 10
// Draw[]> mksweep ww
// Draw[]> addsweep tw
// Draw[]> buildsweep r1 -R
//
// It results in creation of shell with self-interfered face.
// However, "checkshape" does not detect any invalidities.
//
// The algorithm "Evolved" must be improved to process such cases.
// Currently they are not processed and this function is useless.
//=======================================================================
class NormalFunc : public math_MultipleVarFunctionWithGradient
{
public:
NormalFunc(const Adaptor3d_CurveOnSurface& theCOS) :myCOnS(theCOS)
{
}
virtual Standard_Integer NbVariables() const Standard_OVERRIDE
{
return 1;
}
virtual Standard_Boolean Value(const math_Vector& X, Standard_Real& F) Standard_OVERRIDE;
virtual Standard_Boolean Gradient(const math_Vector& X, math_Vector& G) Standard_OVERRIDE;
virtual Standard_Boolean Values(const math_Vector& theX,
Standard_Real& theF,
math_Vector& theG) Standard_OVERRIDE
{
if (!Value(theX, theF))
return Standard_False;
if (!Gradient(theX, theG))
return Standard_False;
return Standard_True;
};
virtual Standard_Boolean Values(const math_Vector& theX,
Standard_Real& theF,
math_Vector& theG,
math_Matrix& theH) Standard_OVERRIDE
{
if (!Values(theX, theF, theG))
return Standard_False;
theH(1, 1) = theG(1);
return Standard_True;
};
Standard_Real FirstParameter() const
{
return myCOnS.FirstParameter();
}
Standard_Real LastParameter() const
{
return myCOnS.LastParameter();
}
gp_Pnt GetPoint(const Standard_Real theX)
{
const Handle(Adaptor2d_Curve2d) &aC = myCOnS.GetCurve();
const Handle(Adaptor3d_Surface) &aS = myCOnS.GetSurface();
const gp_Pnt2d aP2d(aC->Value(theX));
return aS->Value(aP2d.X(), aP2d.Y());
}
protected:
NormalFunc& operator=(NormalFunc&);
private:
const Adaptor3d_CurveOnSurface& myCOnS;
};
//=======================================================================
//function : Value
//purpose : +aD1v_x^2*aD1u_y^2 + aD1v_x^2*aD1u_z^2 +
// +aD1v_y^2*aD1u_z^2 + aD1u_x^2*aD1v_y^2 +
// +aD1u_x^2*aD1v_z^2 + aD1u_y^2*aD1v_z^2 -
// - 2*(+aD1u_x*aD1v_x*aD1u_y*aD1v_y +
// +aD1u_x*aD1v_x*aD1u_z*aD1v_z +
// +aD1u_y*aD1v_y*aD1u_z*aD1v_z)
//=======================================================================
Standard_Boolean NormalFunc::Value(const math_Vector& theX, Standard_Real& theF)
{
const Handle(Adaptor2d_Curve2d) &aC = myCOnS.GetCurve();
const Handle(Adaptor3d_Surface) &aS = myCOnS.GetSurface();
const gp_Pnt2d aP2d(aC->Value(theX(1)));
gp_Pnt aP3d;
gp_Vec aD1u, aD1v;
aS->D1(aP2d.X(), aP2d.Y(), aP3d, aD1u, aD1v);
theF = aD1u.Crossed(aD1v).SquareMagnitude();
return Standard_True;
}
//=======================================================================
//function : Gradient
//purpose :
//2 * ((aD1v_x*aD1u_y)*(aD1u_y*(aD2uv_x*aDc_x + aD2v_x*aDc_y) + aD1v_x*(aD2u_y*aDc_x + aD2uv_y*aDc_y)) +
// (aD1v_x*aD1u_z)*(aD1u_z*(aD2uv_x*aDc_x + aD2v_x*aDc_y) + aD1v_x*(aD2u_z*aDc_x + aD2uv_z*aDc_y)) +
// (aD1v_y*aD1u_z)*(aD1u_z*(aD2uv_y*aDc_x + aD2v_y*aDc_y) + aD1v_y*(aD2u_z*aDc_x + aD2uv_z*aDc_y)) +
// (aD1u_x*aD1v_y)*(aD1u_x*(aD2uv_y*aDc_x + aD2v_y*aDc_y) + aD1v_y*(aD2u_x*aDc_x + aD2uv_x*aDc_y)) +
// (aD1u_x*aD1v_z)*(aD1u_x*(aD2uv_z*aDc_x + aD2v_z*aDc_y) + aD1v_z*(aD2u_x*aDc_x + aD2uv_x*aDc_y)) +
// (aD1u_y*aD1v_z)*(aD1u_y*(aD2uv_z*aDc_x + aD2v_z*aDc_y) + aD1v_z*(aD2u_y*aDc_x + aD2uv_y*aDc_y)) -
//
// (aD2u_x*aDc_x + aD2uv_x*aDc_y)*aD1v_x*aD1u_y*aD1v_y -
// aD1u_x*(aD2uv_x*aDc_x + aD2v_x*aDc_y)*aD1u_y*aD1v_y -
// aD1u_x*aD1v_x*(aD2u_y*aDc_x + aD2uv_y*aDc_y)*aD1v_y -
// aD1u_x*aD1v_x*aD1u_y*(aD2uv_y*aDc_x + aD2v_y*aDc_y) -
//
// (aD2u_x*aDc_x + aD2uv_x*aDc_y)*aD1v_x*aD1u_z*aD1v_z -
// aD1u_x*(aD2uv_x*aDc_x + aD2v_x*aDc_y)*aD1u_z*aD1v_z -
// aD1u_x*aD1v_x*(aD2u_z*aDc_x + aD2uv_z*aDc_y)*aD1v_z -
// aD1u_x*aD1v_x*aD1u_z*(aD2uv_z*aDc_x + aD2v_z*aDc_y) -
//
// (aD2u_y*aDc_x + aD2uv_y*aDc_y)*aD1v_y*aD1u_z*aD1v_z -
// aD1u_y*(aD2uv_y*aDc_x + aD2v_y*aDc_y)*aD1u_z*aD1v_z -
// aD1u_y*aD1v_y*(aD2u_z*aDc_x + aD2uv_z*aDc_y)*aD1v_z -
// aD1u_y*aD1v_y*aD1u_z*(aD2uv_z*aDc_x + aD2v_z*aDc_y))
//=======================================================================
Standard_Boolean NormalFunc::Gradient(const math_Vector& theX, math_Vector& theG)
{
const Handle(Adaptor2d_Curve2d) &aC = myCOnS.GetCurve();
const Handle(Adaptor3d_Surface) &aS = myCOnS.GetSurface();
gp_Pnt2d aP2d;
gp_Vec2d aDc;
aC->D1(theX(1), aP2d, aDc);
gp_Pnt aP3d;
gp_Vec aD1u, aD1v, aD2u, aD2v, aD2uv;
aS->D2(aP2d.X(), aP2d.Y(), aP3d, aD1u, aD1v, aD2u, aD2v, aD2uv);
theG(1) = (aD1v.X()*aD1u.Y())*(aD1u.Y()*(aD2uv.X()*aDc.X() + aD2v.X()*aDc.Y()) +
aD1v.X()*(aD2u.Y()*aDc.X() + aD2uv.Y()*aDc.Y())) +
(aD1v.X()*aD1u.Z())*(aD1u.Z()*(aD2uv.X()*aDc.X() +
aD2v.X()*aDc.Y()) + aD1v.X()*(aD2u.Z()*aDc.X() + aD2uv.Z()*aDc.Y())) +
(aD1v.Y()*aD1u.Z())*(aD1u.Z()*(aD2uv.Y()*aDc.X() + aD2v.Y()*aDc.Y()) +
aD1v.Y()*(aD2u.Z()*aDc.X() + aD2uv.Z()*aDc.Y())) + (aD1u.X()*aD1v.Y())*
(aD1u.X()*(aD2uv.Y()*aDc.X() + aD2v.Y()*aDc.Y()) + aD1v.Y()*(aD2u.X()*
aDc.X() + aD2uv.X()*aDc.Y())) + (aD1u.X()*aD1v.Z())*(aD1u.X()*(aD2uv.Z()*
aDc.X() + aD2v.Z()*aDc.Y()) + aD1v.Z()*(aD2u.X()*aDc.X() +
aD2uv.X()*aDc.Y())) + (aD1u.Y()*aD1v.Z())*(aD1u.Y()*(aD2uv.Z()*aDc.X() +
aD2v.Z()*aDc.Y()) + aD1v.Z()*(aD2u.Y()*aDc.X() + aD2uv.Y()*aDc.Y())) -
(aD2u.X()*aDc.X() + aD2uv.X()*aDc.Y())*aD1v.X()*aD1u.Y()*aD1v.Y() -
aD1u.X()*(aD2uv.X()*aDc.X() + aD2v.X()*aDc.Y())*aD1u.Y()*aD1v.Y() -
aD1u.X()*aD1v.X()*(aD2u.Y()*aDc.X() + aD2uv.Y()*aDc.Y())*aD1v.Y() -
aD1u.X()*aD1v.X()*aD1u.Y()*(aD2uv.Y()*aDc.X() + aD2v.Y()*aDc.Y()) -
(aD2u.X()*aDc.X() + aD2uv.X()*aDc.Y())*aD1v.X()*aD1u.Z()*aD1v.Z() -
aD1u.X()*(aD2uv.X()*aDc.X() + aD2v.X()*aDc.Y())*aD1u.Z()*aD1v.Z() -
aD1u.X()*aD1v.X()*(aD2u.Z()*aDc.X() + aD2uv.Z()*aDc.Y())*aD1v.Z() -
aD1u.X()*aD1v.X()*aD1u.Z()*(aD2uv.Z()*aDc.X() + aD2v.Z()*aDc.Y()) -
(aD2u.Y()*aDc.X() + aD2uv.Y()*aDc.Y())*aD1v.Y()*aD1u.Z()*aD1v.Z() -
aD1u.Y()*(aD2uv.Y()*aDc.X() + aD2v.Y()*aDc.Y())*aD1u.Z()*aD1v.Z() -
aD1u.Y()*aD1v.Y()*(aD2u.Z()*aDc.X() + aD2uv.Z()*aDc.Y())*aD1v.Z() -
aD1u.Y()*aD1v.Y()*aD1u.Z()*(aD2uv.Z()*aDc.X() + aD2v.Z()*aDc.Y());
return Standard_True;
}
#endif
//=======================================================================
// function : RebuildFaces
// purpose : Creates a wires from theEdges and puts it to the new face
// which is empty-copied from theSourceFace.
//=======================================================================
static void RebuildFaces(const TopTools_ListOfShape& theLE,
const TopoDS_Face& theSourceFace,
TopTools_ListOfShape& theList)
{
// build new faces
BOPAlgo_BuilderFace aBF;
TopoDS_Face aF = TopoDS::Face(theSourceFace.Oriented(TopAbs_FORWARD));
aBF.SetFace(aF);
aBF.SetShapes(theLE);
aBF.Perform();
const TopTools_ListOfShape& aLFR = aBF.Areas();
if (aLFR.IsEmpty())
{
theList.Append(theSourceFace);
return;
}
TopTools_ListIteratorOfListOfShape aItFR(aLFR);
for (; aItFR.More(); aItFR.Next())
{
const TopoDS_Shape& aFR = TopoDS::Face(aItFR.Value());
theList.Append(aFR);
}
}
//=======================================================================
// function : MakeEdgeDegenerated
// purpose : Returns TRUE if degenerated edge has been created.
// Every degenerated edge (to split) must be added in theLEdges twice
// with different orientations. Moreover, Degenerated edges cannot be shared.
// Therefore, make copy of them before adding.
//=======================================================================
static Standard_Boolean MakeEdgeDegenerated(const TopoDS_Vertex& theV,
const TopoDS_Face& theFace,
const gp_Pnt2d& thePf,
const gp_Pnt2d& thePl,
TopTools_ListOfShape& theLEdges)
{
BRepAdaptor_Surface anAS(theFace, Standard_False);
const Standard_Real aTol = 2.0 * BRep_Tool::Tolerance(theV);
const Standard_Real aTolU = anAS.UResolution(aTol), aTolV = anAS.VResolution(aTol);
if ((Abs(thePf.X() - thePl.X()) < aTolU) && (Abs(thePf.Y() - thePl.Y()) < aTolV))
return Standard_False;
const TopoDS_Vertex aVf = TopoDS::Vertex(theV.Oriented(TopAbs_FORWARD)),
aVl = TopoDS::Vertex(theV.Oriented(TopAbs_REVERSED));
const gp_XY aV = thePl.XY() - thePf.XY();
const Handle(Geom2d_Line) aL1 = new Geom2d_Line(thePf, gp_Dir2d(aV));
const Handle(Geom2d_Line) aL2 = new Geom2d_Line(thePl, gp_Dir2d(aV.Reversed()));
BRep_Builder aBB;
TopoDS_Edge anEdegen1, anEdegen2;
aBB.MakeEdge(anEdegen1);
aBB.MakeEdge(anEdegen2);
aBB.UpdateEdge(anEdegen1, aL1, theFace, Precision::Confusion());
aBB.UpdateEdge(anEdegen2, aL2, theFace, Precision::Confusion());
anEdegen1.Orientation(TopAbs_FORWARD);
anEdegen2.Orientation(TopAbs_FORWARD);
aBB.Add(anEdegen1, aVf);
aBB.Add(anEdegen1, aVl);
aBB.Add(anEdegen2, aVf);
aBB.Add(anEdegen2, aVl);
aBB.Degenerated(anEdegen1, Standard_True);
aBB.Degenerated(anEdegen2, Standard_True);
const Standard_Real aLPar = aV.Modulus();
aBB.Range(anEdegen1, 0.0, aLPar);
aBB.Range(anEdegen2, 0.0, aLPar);
theLEdges.Append(anEdegen1);
theLEdges.Append(anEdegen2);
return Standard_True;
}
//=================================================================================================
static void InsertEDegenerated(const TopoDS_Face& theFace, TopTools_ListOfShape& theLEdges)
{
BRep_Builder aBB;
TopoDS_Wire aWir;
aBB.MakeWire(aWir);
TopTools_ListIteratorOfListOfShape anItr(theLEdges);
for (; anItr.More(); anItr.Next())
{
const TopoDS_Edge& anE = TopoDS::Edge(anItr.Value());
aBB.Add(aWir, anE);
}
TopTools_IndexedDataMapOfShapeListOfShape aMapVE;
TopExp::MapShapesAndUniqueAncestors(aWir, TopAbs_VERTEX, TopAbs_EDGE, aMapVE);
BRepTools_WireExplorer anExp(aWir, theFace);
TopoDS_Edge anE1 = anExp.Current(), aFirstEdge, aLastEdge;
if (anE1.IsNull())
{
// It is possible if aWir contains
// only INTERNAL/EXTERNAL edges.
return;
}
aFirstEdge = anE1;
anExp.Next();
#if 0
if (!anExp.More())
{
// The wire contains only single edge.
// But this edge can be closed itself (e.g. circle).
TopoDS_Vertex aVf, aVl;
TopExp::Vertices(anE1, aVf, aVl);
if (!aVf.IsNull() && aVf.IsSame(aVl))
{
Standard_Real aF, aL;
const Handle(Geom2d_Curve) aC = BRep_Tool::CurveOnSurface(anE1, theFace, aF, aL);
aF = BRep_Tool::Parameter(aVf, anE1);
aL = BRep_Tool::Parameter(aVl, anE1);
const gp_Pnt2d aPf(aC->Value(aF)), aPl(aC->Value(aL));
MakeEdgeDegenerated(aVf, theFace, aPf, aPl, theLEdges);
}
return;
}
#endif
// Map containing all vertices of degenerated edges
TopTools_MapOfShape aMapVofDE;
{
TopExp_Explorer anExpDE(aWir, TopAbs_EDGE);
for (; anExpDE.More(); anExpDE.Next())
{
const TopoDS_Edge& anE = TopoDS::Edge(anExpDE.Current());
if (!BRep_Tool::Degenerated(anE))
continue;
TopoDS_Vertex aV1, aV2;
TopExp::Vertices(anE, aV1, aV2);
// aV1 and aV2 are SAME vertices
aMapVofDE.Add(aV1);
}
}
for (; anExp.More(); anExp.Next())
{
const TopoDS_Edge& anE2 = anExp.Current();
aLastEdge = anE2;
#if 0
if (anE1.IsSame(anE2))
{
//Exclude a gap between two seam-edges (e.g. cylinder without roofs).
anE1 = anE2;
continue;
}
#endif
const TopoDS_Vertex& aVertCurr = anExp.CurrentVertex();
if (aMapVofDE.Contains(aVertCurr))
{
// Necessary degenerated edge has already been created.
anE1 = anE2;
continue;
}
Standard_Real aF, aL;
const Handle(Geom2d_Curve) aC1 = BRep_Tool::CurveOnSurface(anE1, theFace, aF, aL),
aC2 = BRep_Tool::CurveOnSurface(anE2, theFace, aF, aL);
aF = BRep_Tool::Parameter(aVertCurr, anE1);
aL = BRep_Tool::Parameter(aVertCurr, anE2);
const gp_Pnt2d aPf(aC1->Value(aF)), aPl(aC2->Value(aL));
if (MakeEdgeDegenerated(aVertCurr, theFace, aPf, aPl, theLEdges))
{
aMapVofDE.Add(aVertCurr);
anE1 = anE2;
continue;
}
const TopTools_ListOfShape* anEList = aMapVE.Seek(aVertCurr);
if ((anEList != 0) && (anEList->Extent() <= 2))
{
anE1 = anE2;
continue;
}
// Case like cone with apex. In 2D space all is OK
// (therefore BRepTools_WireExplorer processes this case
// correctly). But in 3D-space, we have several edges with
// the same vertex. Cone apex must be plugged by degenerated edge.
Standard_Boolean hasDegenerated = Standard_False;
anItr.Init(*anEList);
for (; anItr.More(); anItr.Next())
{
const TopoDS_Edge& anEdge = TopoDS::Edge(anItr.Value());
if (BRep_Tool::Degenerated(anEdge))
{
hasDegenerated = Standard_True;
break;
}
}
if (hasDegenerated)
{
anE1 = anE2;
continue;
}
// Look for the pair for anE1 and anE2 edges
for (Standard_Integer i = 0; i < 2; i++)
{
const gp_Pnt2d& aPoint = i ? aPl : aPf;
anItr.Init(*anEList);
for (; anItr.More(); anItr.Next())
{
const TopoDS_Edge& anEdge = TopoDS::Edge(anItr.Value());
if (anEdge.IsSame(anE1) || anEdge.IsSame(anE2))
continue;
const Handle(Geom2d_Curve) aC = BRep_Tool::CurveOnSurface(anEdge, theFace, aF, aL);
aF = BRep_Tool::Parameter(aVertCurr, anEdge);
const gp_Pnt2d aP(aC->Value(aF));
if (MakeEdgeDegenerated(aVertCurr, theFace, aPoint, aP, theLEdges))
{
aMapVofDE.Add(aVertCurr);
i = 2;
break;
}
}
}
anE1 = anE2;
}
if (aFirstEdge.IsNull() || aLastEdge.IsNull())
return;
#if 0
if (aFirstEdge.IsSame(aLastEdge))
{
//Exclude a gap between two seam-edges (e.g. cylinder without bottom-base).
return;
}
#endif
// TopExp::CommonVertex(...) does not work
// if edges have more than one pair of common vertex
//(e.g. two halves of circle). Here, we process this case.
TopoDS_Vertex aV[4];
TopExp::Vertices(aFirstEdge, aV[0], aV[1]);
if (!aV[0].IsNull() && aV[0].IsSame(aV[1]))
{
// Possible reason is the NOT-CLOSED edge
// has only single vertex and is covered by it.
return;
}
TopExp::Vertices(aLastEdge, aV[2], aV[3]);
if (!aV[2].IsNull() && aV[2].IsSame(aV[3]))
{
// Possible reason is the NOT-CLOSED edge
// has only single vertex and is covered by it.
return;
}
for (Standard_Integer anIDFE = 0; anIDFE < 2; anIDFE++)
{
for (Standard_Integer anIDLE = 2; anIDLE < 4; anIDLE++)
{
if (!aV[anIDFE].IsSame(aV[anIDLE]))
continue;
const NCollection_List<TopoDS_Shape>* anEList = aMapVE.Seek(aV[anIDFE]);
if ((anEList != 0) && (anEList->Extent() > 2))
{
// Causes:
// 1. Non-manifold topology.
// 2. Case such as:
//
// *************************
// * *
// seam * * seam
// * edge1 edge2 *
// * ******** ********* *
// V1 V2 V3 V4
//
//
// V1 - vertex between edge1 and seam
// V4 - vertex between edge2 and seam
//
// Indeed, V1 and V4 are same but they
// must not be joined.
continue;
}
Standard_Real aF, aL;
const Handle(Geom2d_Curve) aC1 = BRep_Tool::CurveOnSurface(aFirstEdge, theFace, aF, aL),
aC2 = BRep_Tool::CurveOnSurface(aLastEdge, theFace, aF, aL);
aF = BRep_Tool::Parameter(aV[anIDFE], aFirstEdge);
aL = BRep_Tool::Parameter(aV[anIDLE], aLastEdge);
const gp_Pnt2d aPf(aC1->Value(aF)), aPl(aC2->Value(aL));
MakeEdgeDegenerated(aV[anIDFE], theFace, aPf, aPl, theLEdges);
}
}
}
//=======================================================================
// function : CheckSingularityAndAdd
// purpose : Returns TRUE if theF has been split
//=======================================================================
Standard_Boolean BRepFill_AdvancedEvolved::CheckSingularityAndAdd(
const TopoDS_Face& theF,
const Standard_Real theFuzzyToler,
TopTools_ListOfShape& theListOfFaces,
TopTools_ListOfShape& theListOfSplits) const
{
const BRepAdaptor_Surface anAS(theF, Standard_False);
GeomAbs_SurfaceType aSType = anAS.GetType();
if (aSType == GeomAbs_OffsetSurface)
{
aSType = anAS.BasisSurface()->GetType();
}
if (aSType == GeomAbs_Plane)
{
TopTools_MapOfShape aME;
TopTools_ListOfShape aLE;
TopExp_Explorer anExp(theF, TopAbs_EDGE);
for (; anExp.More(); anExp.Next())
{
const TopoDS_Edge& anE = TopoDS::Edge(anExp.Current());
if (aME.Add(anE))
aLE.Append(anE);
}
// Split interfered edges
BOPAlgo_PaveFiller aPF;
aPF.SetArguments(aLE);
aPF.SetRunParallel(myIsParallel);
aPF.Perform();
if (aPF.HasErrors())
{
theListOfFaces.Append(theF);
return Standard_False;
}
const BOPDS_DS& aDS = aPF.DS();
if (aDS.NbShapes() == aDS.NbSourceShapes())
{
// Interfered edges have not been detected
theListOfFaces.Append(theF);
return Standard_False;
}
BOPAlgo_Builder aBuilder;
aBuilder.SetArguments(aLE);
aBuilder.SetRunParallel(myIsParallel);
aBuilder.PerformWithFiller(aPF);
if (aBuilder.HasErrors())
{
theListOfFaces.Append(theF);
return Standard_False;
}
const TopoDS_Shape& anEdges = aBuilder.Shape();
BRep_Builder aBB;
TopoDS_Compound aCompW, aCompF;
aBB.MakeCompound(aCompW);
aBB.MakeCompound(aCompF);
BOPAlgo_Tools::EdgesToWires(anEdges, aCompW, Standard_True);
BOPAlgo_Tools::WiresToFaces(aCompW, aCompF);
aME.Clear();
anExp.Init(aCompF, TopAbs_FACE);
for (; anExp.More(); anExp.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anExp.Current());
theListOfSplits.Append(aF);
}
return Standard_True;
}
if ((aSType != GeomAbs_Cone) && (aSType != GeomAbs_Sphere) && (aSType != GeomAbs_BezierSurface)
&& (aSType != GeomAbs_BSplineSurface) && (aSType != GeomAbs_SurfaceOfRevolution))
{
theListOfFaces.Append(theF);
return Standard_False;
}
BRep_Builder aBB;
TopoDS_Compound aCWires;
aBB.MakeCompound(aCWires);
Standard_Boolean isSplit = Standard_False;
TopTools_ListOfShape aListEdges;
const TopoDS_Face aFace = TopoDS::Face(theF.Oriented(TopAbs_FORWARD));
for (TopoDS_Iterator anExpW(aFace); anExpW.More(); anExpW.Next())
{
const TopoDS_Wire& aWir = TopoDS::Wire(anExpW.Value());
TopTools_ListOfShape aLGF;
TopExp_Explorer anEExp(aWir, TopAbs_EDGE);
for (; anEExp.More(); anEExp.Next())
{
const TopoDS_Edge& anE = TopoDS::Edge(anEExp.Current());
aLGF.Append(anE);
}
BOPAlgo_PaveFiller aPF;
aPF.SetArguments(aLGF);
aPF.SetFuzzyValue(theFuzzyToler);
aPF.Perform();
if (aPF.HasErrors())
{
continue;
}
const BOPDS_DS& aDS = aPF.DS();
if (aDS.NbShapes() == aDS.NbSourceShapes())
{
// No new shapes have been created
continue;
}
BOPAlgo_Builder aBuilder;
aBuilder.SetArguments(aLGF);
aBuilder.SetRunParallel(myIsParallel);
aBuilder.SetNonDestructive(Standard_True);
aBuilder.PerformWithFiller(aPF);
if (aBuilder.HasErrors())
{
continue;
}
TopTools_ListOfShape aLE;
#if 0
// This fragment requires fixing the issue #29656
TopTools_MapOfShape aMM;
TopExp_Explorer anExpEB(aBAB.Shape(), TopAbs_EDGE);
for (; anExpEB.More(); anExpEB.Next())
{
const TopoDS_Edge anEE = TopoDS::Edge(anExpEB.Current());
if (!aMM.Add(anEE))
continue;
aLE.Append(anEE);
}
#else
TopTools_ListIteratorOfListOfShape aBItr(aLGF);
for (; aBItr.More(); aBItr.Next())
{
const TopoDS_Edge& aSh = TopoDS::Edge(aBItr.Value());
const TopTools_ListOfShape& aLM = aBuilder.Modified(aSh);
if (aLM.IsEmpty() || BRep_Tool::Degenerated(aSh))
{
aLE.Append(aSh);
continue;
}
TopTools_ListIteratorOfListOfShape anItLM(aLM);
for (; anItLM.More(); anItLM.Next())
{
const TopoDS_Edge& anEM = TopoDS::Edge(anItLM.Value());
aLE.Append(anEM);
}
}
#endif
isSplit = Standard_True;
InsertEDegenerated(aFace, aLE);
aListEdges.Append(aLE);
}
if (!isSplit)
{
theListOfFaces.Append(theF);
return Standard_False;
}
RebuildFaces(aListEdges, theF, theListOfSplits);
TopTools_ListIteratorOfListOfShape anItrS(theListOfSplits);
for (; anItrS.More(); anItrS.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anItrS.Value());
theListOfFaces.Append(aF.Oriented(theF.Orientation()));
}
return Standard_True;
}
//=================================================================================================
Standard_Boolean ContainsInList(const TopTools_ListOfShape& theL, const TopoDS_Shape& theObject)
{
TopTools_ListIteratorOfListOfShape anIt(theL);
for (; anIt.More(); anIt.Next())
{
if (anIt.Value().IsSame(theObject))
{
return Standard_True;
}
}
return Standard_False;
}
//=======================================================================
// function: FindInternals
// purpose: Looks for internal shapes inside the face or solid
//=======================================================================
void FindInternals(const TopoDS_Shape& theS, TopTools_ListOfShape& theLInt)
{
TopoDS_Iterator itS(theS);
for (; itS.More(); itS.Next())
{
const TopoDS_Shape& aSS = itS.Value();
if (aSS.Orientation() == TopAbs_INTERNAL)
theLInt.Append(aSS);
else
{
TopoDS_Iterator itSS(aSS);
for (; itSS.More(); itSS.Next())
{
if (itSS.Value().Orientation() == TopAbs_INTERNAL)
{
theLInt.Append(aSS);
break;
}
}
}
}
}
//=======================================================================
// function: RemoveInternalWires
// purpose: Removes internal wires from the faces
//=======================================================================
void RemoveInternalWires(const TopoDS_Shape& theShape)
{
TopExp_Explorer anExpF(theShape, TopAbs_FACE);
for (; anExpF.More(); anExpF.Next())
{
TopoDS_Face& aF = *(TopoDS_Face*)&anExpF.Current();
TopTools_ListOfShape aLWToRemove;
FindInternals(aF, aLWToRemove);
if (aLWToRemove.Extent())
{
aF.Free(Standard_True);
TopTools_ListIteratorOfListOfShape itR(aLWToRemove);
for (; itR.More(); itR.Next())
{
BRep_Builder().Remove(aF, itR.Value());
}
aF.Free(Standard_False);
}
}
}
//=================================================================================================
void ProcessVertex(const TopoDS_Vertex& aV,
const TopTools_ListOfShape& aLE,
const TopTools_ListOfShape& aLF)
{
Standard_Real aTol, aD2, aTolMax2, aTolE, aParam;
gp_Pnt aPC3D;
gp_Pnt2d aPC2D;
TopAbs_Orientation anOrV;
TopTools_ListIteratorOfListOfShape anIt;
TopExp_Explorer aVExp;
BRep_ListIteratorOfListOfCurveRepresentation itcr;
//
aTolMax2 = -1.e6;
//
Handle(BRep_TVertex)& TV = *((Handle(BRep_TVertex)*)&aV.TShape());
const gp_Pnt& aPV3D = TV->Pnt();
aTol = BRep_Tool::Tolerance(aV);
//
anIt.Initialize(aLE);
for (; anIt.More(); anIt.Next())
{
const TopoDS_Edge& aE = TopoDS::Edge(anIt.Value());
//
Handle(BRep_TEdge)& TE = *((Handle(BRep_TEdge)*)&aE.TShape());
const TopLoc_Location& Eloc = aE.Location();
//
aVExp.Init(aE, TopAbs_VERTEX);
for (; aVExp.More(); aVExp.Next())
{
const TopoDS_Vertex& aVx = TopoDS::Vertex(aVExp.Current());
//
if (!aVx.IsSame(aV))
{
continue;
}
//
anOrV = aVx.Orientation();
if (!(anOrV == TopAbs_FORWARD || anOrV == TopAbs_REVERSED))
{
continue;
}
//
const BRep_ListOfCurveRepresentation& aLCR = TE->Curves();
itcr.Initialize(aLCR);
for (; itcr.More(); itcr.Next())
{
const Handle(BRep_CurveRepresentation)& cr = itcr.Value();
const TopLoc_Location& loc = cr->Location();
TopLoc_Location L = (Eloc * loc).Predivided(aV.Location());
//
// 3D-Curve
if (cr->IsCurve3D())
{
const Handle(Geom_Curve)& aC3D = cr->Curve3D();
//
if (aC3D.IsNull())
{
continue;
}
// 3D-point treatment
aParam = BRep_Tool::Parameter(aVx, aE);
aPC3D = aC3D->Value(aParam);
aPC3D.Transform(L.Transformation());
aD2 = aPV3D.SquareDistance(aPC3D);
if (aD2 > aTolMax2)
{
aTolMax2 = aD2;
}
//
} // if (cr->IsCurve3D())
//
// 2D-Curve
else if (cr->IsCurveOnSurface())
{
const Handle(Geom2d_Curve)& aC2D = cr->PCurve();
if (aC2D.IsNull())
{
continue;
}
// Surface
const Handle(Geom_Surface)& aS = cr->Surface();
//
// 2D-point treatment
aParam = BRep_Tool::Parameter(aVx, aE, aS, L);
aPC2D = aC2D->Value(aParam);
aS->D0(aPC2D.X(), aPC2D.Y(), aPC3D);
aPC3D.Transform(L.Transformation());
aD2 = aPV3D.SquareDistance(aPC3D);
if (aD2 > aTolMax2)
{
aTolMax2 = aD2;
}
} // if (cr->IsCurveOnSurface())
} // for (; itcr.More(); itcr.Next())
} // for (; aVExp.More(); aVExp.Next())
} // for (; anIt.More(); anIt.Next())
// #########################################################
//
// Reducing
if (aTolMax2 < 0.)
{
return;
}
//
aTolMax2 = sqrt(aTolMax2);
if (aTolMax2 > aTol)
{
return;
}
//
anIt.Initialize(aLE);
for (; anIt.More(); anIt.Next())
{
const TopoDS_Edge& aE = TopoDS::Edge(anIt.Value());
aTolE = BRep_Tool::Tolerance(aE);
if (aTolMax2 < aTolE)
{
aTolMax2 = aTolE;
}
}
//
anIt.Initialize(aLF);
for (; anIt.More(); anIt.Next())
{
const TopoDS_Face& aF = TopoDS::Face(anIt.Value());
aTolE = BRep_Tool::Tolerance(aF);
if (aTolMax2 < aTolE)
{
aTolMax2 = aTolE;
}
}
//
if (aTolMax2 > aTol)
{
return;
}
//
// Update Tolerance
// with a small margin
TV->Tolerance(aTolMax2 + aTolMax2 * 0.0001);
}
//=================================================================================================
void ReduceVertexTolerance(const TopoDS_Shape& aS)
{
Standard_Integer i, aNbV;
TopTools_IndexedDataMapOfShapeListOfShape aVEMap, aVFMap;
TopExp::MapShapesAndUniqueAncestors(aS, TopAbs_VERTEX, TopAbs_EDGE, aVEMap);
TopExp::MapShapesAndUniqueAncestors(aS, TopAbs_VERTEX, TopAbs_FACE, aVFMap);
aNbV = aVEMap.Extent();
for (i = 1; i <= aNbV; i++)
{
const TopoDS_Vertex& aV = TopoDS::Vertex(aVEMap.FindKey(i));
const TopTools_ListOfShape& aLE = aVEMap(i);
const TopTools_ListOfShape& aLF = aVFMap.FindFromKey(aV);
ProcessVertex(aV, aLE, aLF);
}
}