1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-16 10:08:36 +03:00
occt/src/BRepFill/BRepFill_AdvancedEvolved.cxx
nbv 858435884d 0029523: Problem with BRepOffsetAPI_MakeEvolved
The capabilities of the class BRepOffsetAPI_MakeEvolved have been extended with involving alternate algorithm of resolving the loops in the piped shape. The new option theIsVolume is added for that in the constructor.

New class BRepFill_AdvancedEvolved has been created in order to provide new OCCT-algorithm combining BRepFill_PipeShell and BOPAlgo_MakerVolume.

A change in BOPAlgo_PaveFiller.cxx has been made in order to solve a specific problem of Boolean operation.

The interface of DRAW-command "evolved" has been updated to add the new option. DRAW-command "evolvedsolid" has been deleted. Now it is replaced with DRAW-command "evolved" with the option "-solid".

Testgrid "evolved" has been created.
2019-05-07 14:20:58 +03:00

2035 lines
57 KiB
C++

// 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 <TopExp.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopTools_ListOfShape.hxx>
#include <BOPAlgo_Tools.hxx>
#include <BRepLib_FindSurface.hxx>
#include <Geom_Plane.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BOPAlgo_MakerVolume.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopExp_Explorer.hxx>
#include <BOPAlgo_PaveFiller.hxx>
#include <math_MultipleVarFunctionWithHessian.hxx>
#include <Adaptor3d_CurveOnSurface.hxx>
#include <Adaptor2d_HCurve2d.hxx>
#include <Adaptor3d_HSurface.hxx>
#include <math_NewtonMinimum.hxx>
#include <BOPTools_AlgoTools.hxx>
#include <math_Matrix.hxx>
#include <math_Vector.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <BRepTools_WireExplorer.hxx>
#include <BRepTools.hxx>
#include <BRepTopAdaptor_FClass2d.hxx>
#include <BOPAlgo_BuilderFace.hxx>
#include <BOPAlgo_BuilderFace.hxx>
#include <Geom2d_Line.hxx>
#include <BRepBuilderAPI_Copy.hxx>
#include <math_GlobOptMin.hxx>
#include <Geom_ConicalSurface.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_ListIteratorOfListOfCurveRepresentation.hxx>
#include <BRep_TEdge.hxx>
#include <ShapeUpgrade_UnifySameDomain.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);
//=======================================================================
//function : PerformBoolean
//purpose :
//=======================================================================
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;
}
//=======================================================================
//function : GetSpineAndProfile
//purpose :
//=======================================================================
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;
}
}
//=======================================================================
//function : IsLid
//purpose :
//=======================================================================
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;
}
//=======================================================================
//function : Perform
//purpose :
//=======================================================================
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;
}
//=======================================================================
//function : PerformSweep
//purpose :
//=======================================================================
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();
}
}
//=======================================================================
//function : GetLids
//purpose :
//=======================================================================
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;
}
//Square of the default angular tolerance in
//BOPAlgo_Tools::EdgesToWires(...) and BOPAlgo_Tools::WiresToFaces(...) methods
const Standard_Real aSqAnguarTol = 1.0e-16;
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;
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 (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);
BOPAlgo_Tools::EdgesToWires(aFreeEdges, aCompW, Standard_True);
BOPAlgo_Tools::WiresToFaces(aCompW, aCompF);
{
// 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;
}
//=======================================================================
//function : BuildSolid
//purpose :
//=======================================================================
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;
}
//=======================================================================
//function : UnifyShape
//purpose :
//=======================================================================
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();
}
//=======================================================================
//function : ExtractOuterSolid
//purpose :
//=======================================================================
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();
}
//=======================================================================
//function : RemoveExcessSolids
//purpose :
//=======================================================================
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_HCurve2d) &aC = myCOnS.GetCurve();
const Handle(Adaptor3d_HSurface) &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_HCurve2d) &aC = myCOnS.GetCurve();
const Handle(Adaptor3d_HSurface) &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_HCurve2d) &aC = myCOnS.GetCurve();
const Handle(Adaptor3d_HSurface) &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;
}
//=======================================================================
//function : InsertEDegenerated
//purpose :
//=======================================================================
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;
}
//=======================================================================
//function : ContainsInList
//purpose :
//=======================================================================
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);
}
}
}
//=======================================================================
//function : ProcessVertex
//purpose :
//=======================================================================
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
TV->Tolerance(aTolMax2);
}
//=======================================================================
//function : ReduceVertexTolerance
//purpose :
//=======================================================================
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);
}
}