mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-09 13:22:24 +03:00
0026265: Incorrect result of 2d offset
Additional treatment has been added as the last step of the offset procedure to remove wrong parts (loops) from the result.
This commit is contained in:
@@ -101,6 +101,31 @@
|
||||
#include <TopTools_MapOfShape.hxx>
|
||||
#include <TopTools_SequenceOfShape.hxx>
|
||||
|
||||
#include <TColStd_IndexedMapOfReal.hxx>
|
||||
#include <NCollection_DataMap.hxx>
|
||||
#include <NCollection_QuickSort.hxx>
|
||||
#include <BRepTopAdaptor_FClass2d.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <Geom2dAPI_InterCurveCurve.hxx>
|
||||
#include <BRepTools_ReShape.hxx>
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
#include <Poly_MakeLoops.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <GeomLib.hxx>
|
||||
#include <BRepFill.hxx>
|
||||
#include <ShapeExtend_WireData.hxx>
|
||||
#include <ShapeFix_Wire.hxx>
|
||||
#include <ShapeAnalysis_WireOrder.hxx>
|
||||
#include <ShapeAnalysis_Wire.hxx>
|
||||
#include <NCollection_UBTreeFiller.hxx>
|
||||
#include <BndLib_Add2dCurve.hxx>
|
||||
#include <Bnd_Box2d.hxx>
|
||||
#include <NCollection_DoubleMap.hxx>
|
||||
#include <TColStd_ListOfInteger.hxx>
|
||||
#include <NCollection_UBTree.hxx>
|
||||
#include <NCollection_Array1.hxx>
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef OCCT_DEBUG
|
||||
//#define DRAW
|
||||
@@ -120,6 +145,305 @@ static Standard_Integer NbBISSEC = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//! This struct defines link (i.e. edge) with its vertices and first derivative of pcurves on the both tails of the edge
|
||||
struct TopoLink
|
||||
{
|
||||
TopoDS_Vertex myFV;
|
||||
TopoDS_Vertex myLV;
|
||||
gp_Dir2d myD1L;
|
||||
gp_Dir2d myD1F;
|
||||
};
|
||||
|
||||
typedef NCollection_UBTree <Standard_Integer, Bnd_Box2d> BRepFill_BndBoxTree;
|
||||
|
||||
|
||||
//! This class is used to select overlapping 2d boxes, stored in NCollection::UBTree
|
||||
class BRepFill_BndBoxTreeSelector : public BRepFill_BndBoxTree::Selector
|
||||
{
|
||||
public:
|
||||
//! Defines "edge in intersection" info
|
||||
struct EdgeParam
|
||||
{
|
||||
TopoDS_Edge myEdgeInt; //edge in intersection
|
||||
double myParamInt; // parameter on the edge
|
||||
TopoDS_Vertex myIntVertex; // Vertex of the intersection point
|
||||
};
|
||||
|
||||
public:
|
||||
BRepFill_BndBoxTreeSelector( TopTools_SequenceOfShape& theSeqOfEdges,
|
||||
const TopoDS_Face& theWFace)
|
||||
: BRepFill_BndBoxTreeSelector::Selector(), mySeqOfEdges (theSeqOfEdges), myWFace (theWFace) {}
|
||||
|
||||
BRepFill_BndBoxTreeSelector(const BRepFill_BndBoxTreeSelector& );
|
||||
BRepFill_BndBoxTreeSelector& operator=(const BRepFill_BndBoxTreeSelector& );
|
||||
|
||||
Standard_Boolean Reject (const Bnd_Box2d& theBox) const
|
||||
{
|
||||
return (myCBox.IsOut (theBox));
|
||||
}
|
||||
|
||||
Standard_Boolean Accept (const Standard_Integer& theObj)
|
||||
{
|
||||
//intersection between bounding boxes was found, try to find intersection of edges
|
||||
NCollection_List<NCollection_Array1<int>>::Iterator It(myEdgeIndexes);
|
||||
for (; It.More(); It.Next())
|
||||
{
|
||||
if (It.Value()(1) == myCInd && It.Value()(2) == theObj) //skip already computed intersections
|
||||
return Standard_False;
|
||||
}
|
||||
if (theObj != myCInd) //try to find intersection between two given edges
|
||||
{
|
||||
TopoDS_Edge E1 = TopoDS::Edge(mySeqOfEdges(theObj));
|
||||
TopoDS_Edge E2 = TopoDS::Edge(mySeqOfEdges(myCInd));
|
||||
{
|
||||
Handle_Geom2d_Curve aCur1;
|
||||
double f, l;
|
||||
aCur1 = BRep_Tool::CurveOnSurface(E1, myWFace, f, l );
|
||||
|
||||
Handle_Geom2d_Curve aCur2;
|
||||
double f2, l2;
|
||||
aCur2 = BRep_Tool::CurveOnSurface(E2, myWFace, f2, l2 );
|
||||
|
||||
double IntPrec = Precision::Confusion();
|
||||
Geom2dAPI_InterCurveCurve inter(aCur1, aCur2, IntPrec);
|
||||
|
||||
for (int i = 1; i <= inter.Intersector().NbPoints(); i++)
|
||||
{
|
||||
double Param1 = inter.Intersector().Point(i).ParamOnFirst();
|
||||
double Param2 = inter.Intersector().Point(i).ParamOnSecond();
|
||||
double prec = 1e-5;
|
||||
if (f + prec < Param1 && Param1 < l - prec && f2 + prec < Param2 && Param2 < l2 - prec)
|
||||
{
|
||||
// Save result of intersection to the map (edge -> seq. of parameters on it)
|
||||
if (!myOutMapOfResult.IsBound(E1))
|
||||
{
|
||||
NCollection_Sequence<double> SeqOfParams;
|
||||
SeqOfParams.Append(Param1);
|
||||
myOutMapOfResult.Bind(E1, SeqOfParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
NCollection_Sequence<double> Val = myOutMapOfResult(E1);
|
||||
Val.Append(Param1);
|
||||
myOutMapOfResult.Bind(E1, Val);
|
||||
}
|
||||
|
||||
if (!myOutMapOfResult.IsBound(E2))
|
||||
{
|
||||
NCollection_Sequence<double> SeqOfParams;
|
||||
SeqOfParams.Append(Param2);
|
||||
myOutMapOfResult.Bind(E2, SeqOfParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
NCollection_Sequence<double> Val = myOutMapOfResult(E2);
|
||||
Val.Append(Param2);
|
||||
myOutMapOfResult.Bind(E2, Val);
|
||||
}
|
||||
TopoDS_Vertex V;
|
||||
|
||||
// Make vertex from intersection point
|
||||
double f_1, f_2, l_1, l_2;
|
||||
TopLoc_Location Loc1, Loc2;
|
||||
gp_Pnt p3d1, p3d2;
|
||||
Handle_Geom_Curve aCur1 = BRep_Tool::Curve(E1, Loc1, f_1, l_1 );
|
||||
Handle_Geom_Curve aCur2 = BRep_Tool::Curve(E2, Loc2, f_2, l_2 );
|
||||
aCur1->D0(Param1, p3d1);
|
||||
aCur2->D0(Param2, p3d2);
|
||||
if (!Loc1.IsIdentity())
|
||||
p3d1.Transform(Loc1.Transformation());
|
||||
if (!Loc2.IsIdentity())
|
||||
p3d2.Transform(Loc2.Transformation());
|
||||
gp_Pnt IntPnt((p3d1.X() + p3d2.X())/2., (p3d1.Y() + p3d2.Y())/2., (p3d1.Z() + p3d2.Z())/2.); //middle point of two intersection points of edge1 & edge2
|
||||
double TolE1 = BRep_Tool::Tolerance(E1);
|
||||
double TolE2 = BRep_Tool::Tolerance(E2);
|
||||
|
||||
myBuilder.MakeVertex(V, IntPnt, 1.01* ((TolE1 > TolE2 ? TolE1 : TolE2) + (p3d1.Distance(p3d2)/2.)));
|
||||
|
||||
NCollection_List<BRepFill_BndBoxTreeSelector::EdgeParam> aList;
|
||||
BRepFill_BndBoxTreeSelector::EdgeParam ep;
|
||||
|
||||
ep.myEdgeInt = E1;
|
||||
ep.myParamInt = Param1;
|
||||
ep.myIntVertex = V;
|
||||
myListOfVertexEdgePar.Append(ep);
|
||||
|
||||
ep.myEdgeInt = E2;
|
||||
ep.myParamInt = Param2;
|
||||
ep.myIntVertex = V;
|
||||
myListOfVertexEdgePar.Append(ep);
|
||||
|
||||
NCollection_Array1<int> anIndArr(1, 2);
|
||||
anIndArr(1) = theObj;
|
||||
anIndArr(2) = myCInd;
|
||||
myEdgeIndexes.Append(anIndArr);
|
||||
aCur1.Nullify();
|
||||
aCur2.Nullify();
|
||||
}
|
||||
}
|
||||
aCur1.Nullify();
|
||||
aCur2.Nullify();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else //try to find self-intersection of edge
|
||||
{
|
||||
TopoDS_Edge E1 = TopoDS::Edge(mySeqOfEdges(theObj));
|
||||
{
|
||||
Handle_Geom2d_Curve aCur1;
|
||||
double f, l;
|
||||
aCur1 = BRep_Tool::CurveOnSurface(E1, myWFace, f, l );
|
||||
|
||||
double IntPrec = Precision::Confusion();
|
||||
Geom2dAPI_InterCurveCurve inter(aCur1, IntPrec);
|
||||
|
||||
for (int i = 1; i <= inter.Intersector().NbPoints(); i++)
|
||||
{
|
||||
double Param1 = inter.Intersector().Point(i).ParamOnFirst();
|
||||
double Param2 = inter.Intersector().Point(i).ParamOnSecond();
|
||||
double prec = 1e-5;
|
||||
if (f + prec < Param1 && Param1 < l - prec && f + prec < Param2 && Param2 < l - prec)
|
||||
{
|
||||
// Save result of intersection to the map (edge -> seq. of parameters on it)
|
||||
if (!myOutMapOfResult.IsBound(E1))
|
||||
{
|
||||
NCollection_Sequence<double> SeqOfParams;
|
||||
SeqOfParams.Append(Param1);
|
||||
SeqOfParams.Append(Param2);
|
||||
myOutMapOfResult.Bind(E1, SeqOfParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
NCollection_Sequence<double> Val = myOutMapOfResult(E1);
|
||||
Val.Append(Param1);
|
||||
Val.Append(Param2);
|
||||
myOutMapOfResult.Bind(E1, Val);
|
||||
}
|
||||
|
||||
// Make vertex from intersection point
|
||||
TopoDS_Vertex V;
|
||||
|
||||
double f_1, l_1 ;
|
||||
TopLoc_Location Loc1;
|
||||
gp_Pnt p3d1, p3d2;
|
||||
Handle_Geom_Curve aCur1 = BRep_Tool::Curve(E1, Loc1, f_1, l_1 );
|
||||
aCur1->D0(Param1, p3d1);
|
||||
aCur1->D0(Param2, p3d2);
|
||||
if (!Loc1.IsIdentity())
|
||||
p3d1.Transform(Loc1.Transformation());
|
||||
gp_Pnt IntPnt((p3d1.X() + p3d2.X())/2., (p3d1.Y() + p3d2.Y())/2., (p3d1.Z() + p3d2.Z())/2.);
|
||||
double TolE1 = BRep_Tool::Tolerance(E1);
|
||||
|
||||
myBuilder.MakeVertex(V, IntPnt, 1.01* (TolE1 + (p3d1.Distance(p3d2)/2.)));
|
||||
|
||||
NCollection_List<BRepFill_BndBoxTreeSelector::EdgeParam> aList;
|
||||
BRepFill_BndBoxTreeSelector::EdgeParam ep;
|
||||
|
||||
ep.myEdgeInt = E1;
|
||||
ep.myParamInt = Param1;
|
||||
ep.myIntVertex = V;
|
||||
myListOfVertexEdgePar.Append(ep);
|
||||
|
||||
ep.myEdgeInt = E1;
|
||||
ep.myParamInt = Param2;
|
||||
ep.myIntVertex = V;
|
||||
myListOfVertexEdgePar.Append(ep);
|
||||
|
||||
NCollection_Array1<int> anIndArr(1, 2);
|
||||
anIndArr(1) = theObj;
|
||||
anIndArr(2) = theObj;
|
||||
myEdgeIndexes.Append(anIndArr);
|
||||
aCur1.Nullify();
|
||||
}
|
||||
}
|
||||
aCur1.Nullify();
|
||||
|
||||
}
|
||||
}
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
void ClearResult()
|
||||
{
|
||||
myOutMapOfResult.Clear();
|
||||
}
|
||||
|
||||
void SetCurrentBox (const Bnd_Box2d& theBox, int theInd)
|
||||
{
|
||||
myCBox = theBox;
|
||||
myCInd = theInd;
|
||||
}
|
||||
|
||||
void GetResult( NCollection_DataMap<TopoDS_Edge, NCollection_Sequence<double>>& theOutMapOfResult)
|
||||
{
|
||||
theOutMapOfResult = myOutMapOfResult;
|
||||
}
|
||||
|
||||
void GetListOfVertexEdgePar( NCollection_List<BRepFill_BndBoxTreeSelector::EdgeParam>& theOutList)
|
||||
{
|
||||
theOutList = myListOfVertexEdgePar;
|
||||
}
|
||||
|
||||
private:
|
||||
TopTools_SequenceOfShape& mySeqOfEdges; //edges to be intersected with each other
|
||||
const TopoDS_Face& myWFace; //work spine face
|
||||
NCollection_DataMap<TopoDS_Edge, NCollection_Sequence<double>> myOutMapOfResult; // map "edge to it's intersection parameters"
|
||||
NCollection_List<BRepFill_BndBoxTreeSelector::EdgeParam> myListOfVertexEdgePar;
|
||||
Bnd_Box2d myCBox;
|
||||
int myCInd;
|
||||
NCollection_List<NCollection_Array1<int>> myEdgeIndexes; //used to store already computed edge's indexes
|
||||
BRep_Builder myBuilder;
|
||||
};
|
||||
|
||||
|
||||
class Poly_Helper : public Poly_MakeLoops2D::Helper
|
||||
{
|
||||
public:
|
||||
Poly_Helper(TopTools_IndexedMapOfShape& themN2V,
|
||||
TopTools_IndexedDataMapOfShapeListOfShape& themV2E,
|
||||
NCollection_DoubleMap<Poly_MakeLoops2D::Link, TopoDS_Edge>& themPL2E,
|
||||
NCollection_DataMap<TopoDS_Edge, TopoLink>& themE2EInfo,
|
||||
const NCollection_DataMap<int, Poly_MakeLoops2D::ListOfLink>& themNode2ListOfLinks) :
|
||||
mymN2V (themN2V), mymV2E (themV2E), mymPL2E (themPL2E), mymE2EInfo (themE2EInfo),
|
||||
mymNode2ListOfLinks (themNode2ListOfLinks)
|
||||
{
|
||||
//Poly_MakeLoops2D::Helper();
|
||||
};
|
||||
Poly_Helper(const Poly_Helper& theOther) : Poly_MakeLoops2D::Helper(theOther), mymN2V (theOther.mymN2V), mymV2E (theOther.mymV2E), mymPL2E (theOther.mymPL2E), mymE2EInfo (theOther.mymE2EInfo),
|
||||
mymNode2ListOfLinks (theOther.mymNode2ListOfLinks)
|
||||
{
|
||||
};
|
||||
|
||||
Poly_Helper& operator= (const Poly_Helper &theOther);
|
||||
|
||||
virtual const Poly_MakeLoops2D::ListOfLink& GetAdjacentLinks (Standard_Integer theNode) const
|
||||
{
|
||||
return mymNode2ListOfLinks(theNode);
|
||||
}
|
||||
virtual Standard_Boolean GetFirstTangent(const Poly_MakeLoops2D::Link& theLink, gp_Dir2d& theDir) const
|
||||
{
|
||||
TopoDS_Edge E = mymPL2E.Find1(theLink);
|
||||
theDir = mymE2EInfo(E).myD1F;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual Standard_Boolean GetLastTangent(const Poly_MakeLoops2D::Link& theLink, gp_Dir2d& theDir) const
|
||||
{
|
||||
TopoDS_Edge E = mymPL2E.Find1(theLink);
|
||||
theDir = mymE2EInfo(E).myD1L;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
TopTools_IndexedMapOfShape& mymN2V; //map 'node to vertex'
|
||||
TopTools_IndexedDataMapOfShapeListOfShape& mymV2E;
|
||||
NCollection_DoubleMap<Poly_MakeLoops2D::Link, TopoDS_Edge>& mymPL2E; //map 'link to edge'
|
||||
NCollection_DataMap<TopoDS_Edge, TopoLink>& mymE2EInfo;
|
||||
const NCollection_DataMap<int, Poly_MakeLoops2D::ListOfLink>& mymNode2ListOfLinks; //used internally by poly_makeloops algo
|
||||
|
||||
};
|
||||
|
||||
// Modified by Sergey KHROMOV - Thu Nov 16 17:24:39 2000 Begin
|
||||
|
||||
static void QuasiFleche(const Adaptor3d_Curve& C,
|
||||
@@ -224,6 +548,8 @@ static void MakeOffset
|
||||
|
||||
Standard_Boolean CheckSmallParamOnEdge(const TopoDS_Edge& anEdge);
|
||||
|
||||
static bool RemoveLoops(TopoDS_Shape& theInputSh, const TopoDS_Face& theWorkSpine, const Handle(Geom_Plane)& theRefPlane );
|
||||
|
||||
//=======================================================================
|
||||
//function : KPartCircle
|
||||
//purpose :
|
||||
@@ -1160,6 +1486,8 @@ void BRepFill_OffsetWire::PerformWithBiLo
|
||||
if (!myIsOpenResult)
|
||||
FixHoles();
|
||||
|
||||
RemoveLoops(myShape, myWorkSpine, RefPlane);
|
||||
|
||||
myIsDone = Standard_True;
|
||||
}
|
||||
|
||||
@@ -2775,3 +3103,459 @@ Standard_Boolean CheckSmallParamOnEdge(const TopoDS_Edge& anEdge)
|
||||
}
|
||||
|
||||
|
||||
//! Used to remove loops from offset result
|
||||
static bool RemoveLoops(TopoDS_Shape& theInputSh, const TopoDS_Face& theWorkSpine, const Handle(Geom_Plane)& theRefPlane )
|
||||
{
|
||||
Handle(BRepTools_ReShape) ExtReShape = new BRepTools_ReShape;
|
||||
|
||||
TopExp_Explorer Exp( theInputSh, TopAbs_WIRE );
|
||||
|
||||
for (; Exp.More(); Exp.Next())
|
||||
{
|
||||
Handle(BRepTools_ReShape) reshape = new BRepTools_ReShape;
|
||||
TopoDS_Wire InitialW = TopoDS::Wire( Exp.Current() );
|
||||
if (!InitialW.Closed())
|
||||
continue;
|
||||
TopoDS_Wire aW = TopoDS::Wire( Exp.Current() );
|
||||
|
||||
TopExp_Explorer ExpE( aW, TopAbs_EDGE );
|
||||
TopTools_SequenceOfShape Seq;
|
||||
for (; ExpE.More(); ExpE.Next())
|
||||
Seq.Append( ExpE.Current() );
|
||||
|
||||
NCollection_DataMap<TopoDS_Edge, NCollection_Sequence<double>> ME2IP; //map edge to params on this edges
|
||||
gp_Pln pl = theRefPlane->Pln();
|
||||
|
||||
//Prepare UBTree filler
|
||||
// Used to speedup the intersection process by using overlapped 2d bounding boxes
|
||||
BRepFill_BndBoxTree aTree;
|
||||
NCollection_UBTreeFiller <Standard_Integer, Bnd_Box2d> aTreeFiller (aTree);
|
||||
|
||||
BRepFill_BndBoxTreeSelector aSelector(Seq, theWorkSpine);
|
||||
|
||||
// Prepare bounding boxes
|
||||
NCollection_Sequence<Bnd_Box2d> BndBoxesOfEdges;
|
||||
for (int i = 1; i <= Seq.Length(); i++)
|
||||
{
|
||||
double f, l;
|
||||
Handle_Geom2d_Curve aCur = BRep_Tool::CurveOnSurface(TopoDS::Edge(Seq(i)), theWorkSpine, f, l );
|
||||
Bnd_Box2d aBox;
|
||||
BndLib_Add2dCurve::Add( aCur, f, l, 0., aBox );
|
||||
//aBox.Enlarge(1e-4);
|
||||
aTreeFiller.Add(i, aBox);
|
||||
BndBoxesOfEdges.Append(aBox);
|
||||
}
|
||||
|
||||
aTreeFiller.Fill();
|
||||
|
||||
//Perform searching and intersecting of edges
|
||||
aSelector.ClearResult();
|
||||
for (int i = 1; i <= BndBoxesOfEdges.Size(); i++)
|
||||
{
|
||||
aSelector.SetCurrentBox(BndBoxesOfEdges(i), i);
|
||||
aTree.Select(aSelector);
|
||||
}
|
||||
|
||||
aSelector.GetResult(ME2IP); //Retrieve result from algo
|
||||
NCollection_List<BRepFill_BndBoxTreeSelector::EdgeParam> LVEP;
|
||||
aSelector.GetListOfVertexEdgePar(LVEP);
|
||||
|
||||
if (ME2IP.IsEmpty())
|
||||
continue; //if no intersection point => go to the next wire
|
||||
|
||||
TopTools_MapOfShape InterV;
|
||||
TopTools_IndexedMapOfShape EdgesInInter;
|
||||
|
||||
for (NCollection_DataMap<TopoDS_Edge, NCollection_Sequence<double>>::Iterator aMapIt (ME2IP); aMapIt.More(); aMapIt.Next())
|
||||
{
|
||||
TopoDS_Edge E = aMapIt.Key();
|
||||
NCollection_Sequence<double> Params = aMapIt.Value();
|
||||
Handle_Geom_Curve aCur;
|
||||
double f, l;
|
||||
aCur = BRep_Tool::Curve(E, f, l );
|
||||
|
||||
//prepare params on the edge
|
||||
NCollection_Sequence<double> ParamSeq;
|
||||
ParamSeq.Append(f);
|
||||
ParamSeq.Append(l);
|
||||
ParamSeq.Append(Params);
|
||||
|
||||
//sort parameters
|
||||
NCollection_QuickSort<NCollection_Sequence<double>, double>::Perform(ParamSeq, NCollection_Comparator<double>(), ParamSeq.Lower(), ParamSeq.Upper());
|
||||
NCollection_Sequence<TopoDS_Vertex> aVOnEdge; //Vertexes on the edge which divide it in the intersection points into sequence of edges
|
||||
NCollection_Sequence<TopoDS_Edge> NewEdgeSeq;
|
||||
TopoDS_Vertex VF, VL;
|
||||
VF = TopExp::FirstVertex(E);
|
||||
VL = TopExp::LastVertex(E);
|
||||
aVOnEdge.Append(VF);
|
||||
|
||||
for (int i = 2; i <= ParamSeq.Length() - 1; i++)
|
||||
{
|
||||
double P = ParamSeq(i);
|
||||
TopoDS_Vertex MV;
|
||||
for (NCollection_List<BRepFill_BndBoxTreeSelector::EdgeParam>::Iterator anIt (LVEP); anIt.More(); anIt.Next())
|
||||
{
|
||||
BRepFill_BndBoxTreeSelector::EdgeParam ep = anIt.Value();
|
||||
if (ep.myEdgeInt == E && ep.myParamInt == P)
|
||||
{
|
||||
MV = anIt.Value().myIntVertex;
|
||||
InterV.Add(MV);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
aVOnEdge.Append(MV);
|
||||
}
|
||||
aVOnEdge.Append(VL);
|
||||
|
||||
//Split old edge => Construct a new sequence of new edges
|
||||
TopoDS_Edge DE;
|
||||
for (int j = 1; j < aVOnEdge.Length(); j++)
|
||||
{
|
||||
DE = BRepBuilderAPI_MakeEdge(aCur, aVOnEdge(j), aVOnEdge(j+1), ParamSeq(j), ParamSeq(j+1));
|
||||
BRep_Builder BB;
|
||||
BB.UpdateEdge(DE, BRep_Tool::Tolerance(E));
|
||||
NewEdgeSeq.Append(DE);
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire MW;
|
||||
for (int i = 1; i <= NewEdgeSeq.Length(); i++)
|
||||
{
|
||||
MW.Add(NewEdgeSeq(i));
|
||||
EdgesInInter.Add(NewEdgeSeq(i));
|
||||
}
|
||||
MW.Build();
|
||||
TopoDS_Wire TW = MW.Wire(); //make wire from the sequence of edges
|
||||
TW.Orientation(E.Orientation());
|
||||
reshape->Replace(E, TW); //replace old edge with wire
|
||||
}
|
||||
|
||||
aW = TopoDS::Wire(reshape->Apply(aW));
|
||||
|
||||
// Prepare wire for Poly_MakeLoops algo:
|
||||
// Insert neccesary vertices if two edges shares same (two) vertices
|
||||
bool Stat = true;
|
||||
for (int i = 1; i <= EdgesInInter.Extent() && Stat; i++)
|
||||
for (int j = i; j <= EdgesInInter.Extent() && Stat; j++)
|
||||
{
|
||||
TopoDS_Edge E1 = TopoDS::Edge(EdgesInInter(i));
|
||||
TopoDS_Edge E2 = TopoDS::Edge(EdgesInInter(j));
|
||||
if (E1 == E2)
|
||||
continue;
|
||||
TopoDS_Vertex VF1, VL1, VF2, VL2;
|
||||
TopExp::Vertices(E1, VF1, VL1);
|
||||
TopExp::Vertices(E2, VF2, VL2);
|
||||
if ((VF1.IsSame(VF2) && VL1.IsSame(VL2)) || (VF1.IsSame(VL2) && VL1.IsSame(VF2)))
|
||||
{
|
||||
gp_Pnt MP;
|
||||
Handle_Geom_Curve cur;
|
||||
double f, l;
|
||||
cur = BRep_Tool::Curve(E1, f, l);
|
||||
cur->D0(f + (l-f)/2., MP);
|
||||
TopoDS_Vertex MV = BRepLib_MakeVertex(MP);
|
||||
TopoDS_Edge DE1, DE2;
|
||||
BRepBuilderAPI_MakeEdge MEB;
|
||||
MEB.Init(cur, VF1, MV, f, f + (l-f)/2 );
|
||||
if (!MEB.IsDone()) {
|
||||
Stat = false;
|
||||
break;
|
||||
}
|
||||
DE1 = MEB.Edge();
|
||||
MEB.Init(cur, MV, VL1, f + (l-f)/2, l );
|
||||
if (!MEB.IsDone()) {
|
||||
Stat = false;
|
||||
break;
|
||||
}
|
||||
DE2 = MEB.Edge();
|
||||
TopoDS_Wire W = BRepBuilderAPI_MakeWire(DE1, DE2);
|
||||
TopTools_IndexedMapOfShape DummyM;
|
||||
TopExp::MapShapes(W, TopAbs_VERTEX, DummyM);
|
||||
if (DummyM.Extent() !=3 )
|
||||
{
|
||||
Stat = false;
|
||||
break;
|
||||
}
|
||||
reshape->Replace(E1, W.Oriented(E1.Orientation()));
|
||||
}
|
||||
}
|
||||
|
||||
aW = TopoDS::Wire(reshape->Apply(aW));
|
||||
// If edges contains only one vertex => insert another two vertices
|
||||
ExpE.Init( aW, TopAbs_EDGE );
|
||||
for (; ExpE.More() && Stat; ExpE.Next())
|
||||
{
|
||||
TopoDS_Edge E = TopoDS::Edge(ExpE.Current());
|
||||
TopoDS_Vertex VF, VL;
|
||||
TopExp::Vertices(E, VF, VL);
|
||||
|
||||
if (VF.IsSame( VL ) && (InterV.Contains(VL) || InterV.Contains(VF)))
|
||||
{
|
||||
gp_Pnt MP1, MP2;
|
||||
Handle_Geom_Curve cur;
|
||||
double f, l;
|
||||
cur = BRep_Tool::Curve(E, f, l);
|
||||
if ( Abs(l - f ) < 3 * Precision::Confusion())
|
||||
continue;
|
||||
cur->D0(f + (0.3)*(l-f), MP1);
|
||||
cur->D0(f + (0.6)*(l-f), MP2);
|
||||
TopoDS_Vertex MV1 = BRepLib_MakeVertex(MP1);
|
||||
TopoDS_Vertex MV2 = BRepLib_MakeVertex(MP2);
|
||||
BRepBuilderAPI_MakeEdge MEB;
|
||||
TopoDS_Edge DE1, DE2, DE3;
|
||||
MEB.Init(cur, VF, MV1, f, f + (0.3)*(l-f) );
|
||||
if (!MEB.IsDone()) {
|
||||
Stat = false;
|
||||
break;
|
||||
}
|
||||
DE1 = MEB.Edge();
|
||||
MEB.Init(cur, MV1, MV2, f + (0.3)*(l-f), f + (0.6)*(l-f) );
|
||||
if (!MEB.IsDone()) {
|
||||
Stat = false;
|
||||
break;
|
||||
}
|
||||
DE2 = MEB.Edge();
|
||||
MEB.Init(cur, MV2, VL, f + (0.6)*(l-f), l );
|
||||
if (!MEB.IsDone()) {
|
||||
Stat = false;
|
||||
break;
|
||||
}
|
||||
DE3 = MEB.Edge();
|
||||
TopoDS_Wire W = BRepBuilderAPI_MakeWire(DE1, DE2, DE3);
|
||||
TopTools_IndexedMapOfShape DummyM;
|
||||
TopExp::MapShapes(W, TopAbs_VERTEX, DummyM);
|
||||
if (DummyM.Extent() !=3 )
|
||||
{
|
||||
Stat = false;
|
||||
break;
|
||||
}
|
||||
reshape->Replace(E, W.Oriented(E.Orientation()));
|
||||
}
|
||||
}
|
||||
if (!Stat)
|
||||
continue;
|
||||
|
||||
//Perform reorder of wire
|
||||
aW = TopoDS::Wire(reshape->Apply(aW));
|
||||
Handle(ShapeExtend_WireData) aWireData = new ShapeExtend_WireData;
|
||||
Handle(ShapeFix_Wire) aShFixWire = new ShapeFix_Wire;
|
||||
|
||||
Handle(ShapeAnalysis_Wire) aWireAnalyzer;
|
||||
ShapeAnalysis_WireOrder aWireOrder;
|
||||
|
||||
aShFixWire->Load(aWireData);
|
||||
aShFixWire->SetPrecision(1e-7);
|
||||
|
||||
TopExp_Explorer Exp1( aW, TopAbs_EDGE );
|
||||
for (; Exp1.More(); Exp1.Next())
|
||||
aWireData->Add(TopoDS::Edge(Exp1.Current()));
|
||||
|
||||
aWireOrder.KeepLoopsMode() = 0;
|
||||
aWireAnalyzer = aShFixWire->Analyzer();
|
||||
aShFixWire->ModifyTopologyMode() = Standard_True;
|
||||
//aShFixWire->FixConnected(1e-7);
|
||||
aWireAnalyzer->CheckOrder(aWireOrder, Standard_True);
|
||||
aWireOrder.Perform(1);
|
||||
aShFixWire->ClosedWireMode() = 1;
|
||||
aShFixWire->FixReorder(aWireOrder);
|
||||
//aShFixWire->FixDegenerated();
|
||||
bool IsDone = !aShFixWire->StatusReorder(ShapeExtend_FAIL);
|
||||
|
||||
if (!IsDone)
|
||||
continue;
|
||||
|
||||
aW = aWireData->Wire();
|
||||
|
||||
|
||||
if (Stat)
|
||||
{
|
||||
aW = TopoDS::Wire(reshape->Apply(aW));
|
||||
|
||||
// Prepare 'TopoLink' info for Poly_MakeLoops algo => Calculate derivatives of the edges
|
||||
NCollection_DataMap<TopoDS_Edge, TopoLink> mE2EInfo;
|
||||
ExpE.Init(aW, TopAbs_EDGE);
|
||||
for (; ExpE.More(); ExpE.Next())
|
||||
{
|
||||
TopoLink anEngeInfo;
|
||||
TopoDS_Edge E = TopoDS::Edge(ExpE.Current());
|
||||
Handle_Geom2d_Curve aCur;
|
||||
double f, l;
|
||||
gp_Pnt2d Pnt;
|
||||
gp_Vec2d Vec;
|
||||
|
||||
aCur = BRep_Tool::CurveOnSurface(E, theWorkSpine, f, l );
|
||||
if (aCur.IsNull())
|
||||
continue;
|
||||
if (E.Orientation() == TopAbs_FORWARD)
|
||||
{
|
||||
anEngeInfo.myFV = TopExp::FirstVertex(E);
|
||||
anEngeInfo.myLV = TopExp::LastVertex(E);
|
||||
aCur->D1(f, Pnt, Vec);
|
||||
anEngeInfo.myD1F.SetCoord(Vec.X(), Vec.Y());
|
||||
aCur->D1(l, Pnt, Vec);
|
||||
anEngeInfo.myD1L.SetCoord(Vec.X(), Vec.Y());
|
||||
}
|
||||
else
|
||||
{
|
||||
anEngeInfo.myFV = TopExp::LastVertex(E);
|
||||
anEngeInfo.myLV = TopExp::FirstVertex(E);
|
||||
aCur->D1(l, Pnt, Vec);
|
||||
anEngeInfo.myD1F.SetCoord(-Vec.X(), -Vec.Y());
|
||||
aCur->D1(f, Pnt, Vec);
|
||||
anEngeInfo.myD1L.SetCoord(-Vec.X(), -Vec.Y());
|
||||
}
|
||||
mE2EInfo.Bind(E, anEngeInfo);
|
||||
}
|
||||
|
||||
TopTools_IndexedMapOfShape mN2V;
|
||||
TopExp::MapShapes(aW, TopAbs_VERTEX, mN2V);
|
||||
|
||||
TopTools_IndexedDataMapOfShapeListOfShape mV2E;
|
||||
TopExp::MapShapesAndAncestors(aW, TopAbs_VERTEX, TopAbs_EDGE, mV2E);
|
||||
|
||||
//Create links for Poly_MakeLoops algo and bind them to the existing edges
|
||||
NCollection_DoubleMap<Poly_MakeLoops2D::Link, TopoDS_Edge> mPL2E;
|
||||
ExpE.Init(aW, TopAbs_EDGE);
|
||||
for (; ExpE.More(); ExpE.Next())
|
||||
{
|
||||
TopoDS_Edge E = TopoDS::Edge(ExpE.Current());
|
||||
if (!mE2EInfo.IsBound(E))
|
||||
continue;
|
||||
TopoLink L = mE2EInfo(E);
|
||||
int Node1 = mN2V.FindIndex(L.myFV);
|
||||
int Node2 = mN2V.FindIndex(L.myLV);
|
||||
Poly_MakeLoops2D::Link aLink(Node1, Node2);
|
||||
aLink.flags = Poly_MakeLoops2D::LF_Fwd;
|
||||
mPL2E.Bind(aLink, E);
|
||||
}
|
||||
|
||||
NCollection_DataMap<int, Poly_MakeLoops2D::ListOfLink> mNode2ListOfLinks;
|
||||
for (int i = 1; i <= mN2V.Extent(); i++)
|
||||
{
|
||||
TopoDS_Vertex V = TopoDS::Vertex(mN2V(i));
|
||||
TopTools_ListOfShape Edges = mV2E.FindFromKey(V);
|
||||
TopTools_ListIteratorOfListOfShape It(Edges);
|
||||
Poly_MakeLoops2D::ListOfLink aListOfLinks;
|
||||
for (;It.More(); It.Next())
|
||||
{
|
||||
TopoDS_Edge E = TopoDS::Edge(It.Value());
|
||||
if (!mPL2E.IsBound2(E))
|
||||
continue;
|
||||
Poly_MakeLoops2D::Link aL = mPL2E.Find2(E);
|
||||
aListOfLinks.Append(aL);
|
||||
}
|
||||
mNode2ListOfLinks.Bind(i, aListOfLinks);
|
||||
}
|
||||
|
||||
Poly_Helper helper(mN2V, mV2E, mPL2E, mE2EInfo, mNode2ListOfLinks);
|
||||
Poly_MakeLoops2D aLoopMaker(1, &helper, NCollection_BaseAllocator::CommonBaseAllocator() );
|
||||
for (NCollection_DoubleMap<Poly_MakeLoops2D::Link, TopoDS_Edge>::Iterator aMapIt (mPL2E); aMapIt.More(); aMapIt.Next())
|
||||
aLoopMaker.AddLink(aMapIt.Key1());
|
||||
|
||||
aLoopMaker.Perform(); //try to find loops
|
||||
int NbLoops = aLoopMaker.GetNbLoops();
|
||||
int NbHangs = aLoopMaker.GetNbHanging();
|
||||
|
||||
if (NbLoops == 0 || NbHangs != 0 )
|
||||
continue;
|
||||
|
||||
NCollection_Sequence<TopoDS_Wire> aLoops;
|
||||
for (int i = 1; i <= NbLoops; i++) //try to construct loops
|
||||
{
|
||||
Poly_MakeLoops2D::Loop aLoop = aLoopMaker.GetLoop(i);
|
||||
Poly_MakeLoops2D::Loop::Iterator it(aLoop);
|
||||
BRepBuilderAPI_MakeWire aWM;
|
||||
TopoDS_Edge E;
|
||||
for (;it.More(); it.Next())
|
||||
{
|
||||
E = mPL2E.Find1(it.Value());
|
||||
aWM.Add(E);
|
||||
}
|
||||
if (aWM.IsDone())
|
||||
{
|
||||
TopoDS_Wire W = aWM.Wire();
|
||||
if (!W.Closed())
|
||||
{
|
||||
Stat = false;
|
||||
break;
|
||||
}
|
||||
aLoops.Append(W);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Stat)
|
||||
continue;
|
||||
|
||||
// try to classify wires
|
||||
NCollection_Sequence<TopoDS_Wire> InnerMWires; // interior wires
|
||||
NCollection_Sequence<TopoDS_Wire> ExtMWires; //wires which defines a hole
|
||||
for (int i = 1; i <= aLoops.Length(); i++)
|
||||
{
|
||||
TopoDS_Face af = BRepBuilderAPI_MakeFace (theRefPlane, Precision::Confusion() ); //TopoDS::Face ( myWorkSpine.EmptyCopied() );
|
||||
af.Orientation ( TopAbs_REVERSED );
|
||||
BRep_Builder BB;
|
||||
BB.Add (af, aLoops(i));
|
||||
|
||||
BRepTopAdaptor_FClass2d FClass(af, Precision::PConfusion());
|
||||
if (FClass.PerformInfinitePoint() == TopAbs_OUT)
|
||||
InnerMWires.Append(aLoops(i));
|
||||
else
|
||||
ExtMWires.Append(aLoops(i));
|
||||
}
|
||||
|
||||
if (InnerMWires.Length() == ExtMWires.Length())
|
||||
continue;
|
||||
|
||||
if (InnerMWires.Length() < ExtMWires.Length())
|
||||
//probably incorrect orientation
|
||||
continue;
|
||||
//try to find an outer wire
|
||||
int IndOfOuterW = -1;
|
||||
for (int i = 1; i <= InnerMWires.Length(); i++)
|
||||
{
|
||||
bool IsInside = true;
|
||||
BRepBuilderAPI_MakeFace aDB(theRefPlane, InnerMWires(i));
|
||||
TopoDS_Face aDummyFace = TopoDS::Face(aDB.Shape());
|
||||
BRepTopAdaptor_FClass2d FClass(aDummyFace, Precision::PConfusion());
|
||||
for (int j = 1; j <= InnerMWires.Length(); j++)
|
||||
{
|
||||
if ( i == j )
|
||||
continue;
|
||||
double f, l;
|
||||
TopExp_Explorer ExpE( InnerMWires(j), TopAbs_EDGE );
|
||||
Handle_Geom2d_Curve aCur = BRep_Tool::CurveOnSurface(TopoDS::Edge(ExpE.Current()), theWorkSpine, f, l );
|
||||
|
||||
gp_Pnt2d MP = aCur->Value((l + f) / 2.0);
|
||||
if (FClass.Perform(MP) != TopAbs_IN)
|
||||
{
|
||||
IsInside = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (IsInside)
|
||||
{
|
||||
IndOfOuterW = i;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (IndOfOuterW == -1)
|
||||
continue; //cant find an outer wire
|
||||
|
||||
TopoDS_Wire OuterWire = InnerMWires(IndOfOuterW);
|
||||
//make compound: outer wire + holes
|
||||
BRep_Builder BBC;
|
||||
TopoDS_Compound Co;
|
||||
BBC.MakeCompound(Co);
|
||||
BBC.Add(Co, OuterWire);
|
||||
|
||||
for (int i = 1; i <= ExtMWires.Length(); i++)
|
||||
BBC.Add(Co, ExtMWires(i));
|
||||
|
||||
ExtReShape->Replace(InitialW, Co);
|
||||
}
|
||||
}
|
||||
|
||||
theInputSh = ExtReShape->Apply(theInputSh);
|
||||
return true;
|
||||
}
|
Reference in New Issue
Block a user