1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00
occt/src/BRepTools/BRepTools_WireExplorer.cxx
abv 42cf5bc1ca 0024002: Overall code and build procedure refactoring -- automatic
Automatic upgrade of OCCT code by command "occt_upgrade . -nocdl":
- WOK-generated header files from inc and sources from drv are moved to src
- CDL files removed
- All packages are converted to nocdlpack
2015-07-12 07:42:38 +03:00

746 lines
21 KiB
C++

// Created on: 1993-01-21
// Created by: Remi LEQUETTE
// Copyright (c) 1993-1999 Matra Datavision
// Copyright (c) 1999-2014 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 <BRep_Tool.hxx>
#include <BRepTools.hxx>
#include <BRepTools_WireExplorer.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom_Surface.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <gp_Pnt2d.hxx>
#include <Precision.hxx>
#include <Standard_DomainError.hxx>
#include <Standard_NoMoreObject.hxx>
#include <Standard_NoSuchObject.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Wire.hxx>
#include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_MapIteratorOfMapOfShape.hxx>
#include <TopTools_MapOfShape.hxx>
//=======================================================================
// forward declarations of aux functions
//=======================================================================
static Standard_Boolean SelectDouble(TopTools_MapOfShape& Doubles,
TopTools_ListOfShape& L,
TopoDS_Edge& E);
static Standard_Boolean SelectDegenerated(TopTools_ListOfShape& L,
TopoDS_Edge& E);
static Standard_Real GetNextParamOnPC(const Handle(Geom2d_Curve)& aPC,
const gp_Pnt2d& aPRef,
const Standard_Real& fP,
const Standard_Real& lP,
const Standard_Real& tolU,
const Standard_Real& tolV,
const Standard_Boolean& reverse);
//=======================================================================
//function : BRepTools_WireExplorer
//purpose :
//=======================================================================
BRepTools_WireExplorer::BRepTools_WireExplorer()
{
}
//=======================================================================
//function : BRepTools_WireExplorer
//purpose :
//=======================================================================
BRepTools_WireExplorer::BRepTools_WireExplorer(const TopoDS_Wire& W)
{
TopoDS_Face F = TopoDS_Face();
Init(W,F);
}
//=======================================================================
//function : BRepTools_WireExplorer
//purpose :
//=======================================================================
BRepTools_WireExplorer::BRepTools_WireExplorer(const TopoDS_Wire& W,
const TopoDS_Face& F)
{
Init(W,F);
}
//=======================================================================
//function : Init
//purpose :
//=======================================================================
void BRepTools_WireExplorer::Init(const TopoDS_Wire& W)
{
TopoDS_Face F = TopoDS_Face();
Init(W,F);
}
//=======================================================================
//function : Init
//purpose :
//=======================================================================
void BRepTools_WireExplorer::Init(const TopoDS_Wire& W,
const TopoDS_Face& F)
{
myEdge = TopoDS_Edge();
myVertex = TopoDS_Vertex();
myMap.Clear();
myDoubles.Clear();
if( W.IsNull() )
return;
myFace = F;
Standard_Real dfVertToler = 0.;
myReverse = Standard_False;
if (!myFace.IsNull())
{
BRepTools::Update(myFace);
TopLoc_Location aL;
const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(myFace, aL);
GeomAdaptor_Surface aGAS(aSurf);
TopExp_Explorer anExp(W, TopAbs_VERTEX);
for(; anExp.More(); anExp.Next())
{
const TopoDS_Vertex& aV = TopoDS::Vertex(anExp.Current());
dfVertToler = Max(BRep_Tool::Tolerance(aV), dfVertToler);
}
myTolU = 2. * aGAS.UResolution(dfVertToler);
myTolV = 2. * aGAS.VResolution(dfVertToler);
// uresolution for cone with infinite vmin vmax is too small.
if(aGAS.GetType() == GeomAbs_Cone)
{
Standard_Real u1, u2, v1, v2;
BRepTools::UVBounds(myFace, u1, u2, v1, v2);
gp_Pnt aP;
gp_Vec aD1U, aD1V;
aGAS.D1(u1, v1, aP, aD1U, aD1V);
Standard_Real tol1, tol2, maxtol = .0005*(u2-u1);
Standard_Real a = aD1U.Magnitude();
if(a <= Precision::Confusion())
tol1 = maxtol;
else
tol1 = Min(maxtol, dfVertToler/a);
aGAS.D1(u1, v2, aP, aD1U, aD1V);
a = aD1U.Magnitude();
if(a <= Precision::Confusion())
tol2 = maxtol;
else
tol2 = Min(maxtol, dfVertToler/a);
myTolU = 2. * Max(tol1, tol2);
}
if( aGAS.GetType() == GeomAbs_BSplineSurface ||
aGAS.GetType() == GeomAbs_BezierSurface )
{
Standard_Real maxTol = Max(myTolU,myTolV);
myTolU = maxTol;
myTolV = maxTol;
}
myReverse = (myFace.Orientation() == TopAbs_REVERSED);
}
// map of vertices to know if the wire is open
TopTools_MapOfShape vmap;
// Modified by Sergey KHROMOV - Mon May 13 11:50:48 2002 Begin
// map of infinite edges
TopTools_MapOfShape anInfEmap;
// Modified by Sergey KHROMOV - Mon May 13 11:50:49 2002 End
// list the vertices
TopoDS_Vertex V1,V2;
TopTools_ListOfShape empty;
TopoDS_Iterator it(W);
while (it.More())
{
const TopoDS_Edge& E = TopoDS::Edge(it.Value());
TopAbs_Orientation Eori = E.Orientation();
if (Eori == TopAbs_INTERNAL || Eori == TopAbs_EXTERNAL)
{
it.Next();
continue;
}
TopExp::Vertices(E,V1,V2,Standard_True);
if( !V1.IsNull() )
{
if( !myMap.IsBound(V1) )
myMap.Bind(V1,empty);
myMap(V1).Append(E);
// add or remove in the vertex map
V1.Orientation(TopAbs_FORWARD);
if( !vmap.Add(V1) )
vmap.Remove(V1);
}
if( !V2.IsNull() )
{
V2.Orientation(TopAbs_REVERSED);
if(!vmap.Add(V2))
vmap.Remove(V2);
}
// Modified by Sergey KHROMOV - Mon May 13 11:52:20 2002 Begin
if (V1.IsNull() || V2.IsNull())
{
Standard_Real aF = 0., aL = 0.;
BRep_Tool::Range(E, aF, aL);
if(Eori == TopAbs_FORWARD)
{
if (aF == -Precision::Infinite())
anInfEmap.Add(E);
}
else
{ // Eori == TopAbs_REVERSED
if (aL == Precision::Infinite())
anInfEmap.Add(E);
}
}
// Modified by Sergey KHROMOV - Mon May 13 11:52:20 2002 End
it.Next();
}
//Construction of the set of double edges.
TopoDS_Iterator it2(W);
TopTools_MapOfShape emap;
while (it2.More()) {
if (!emap.Add(it2.Value()))
myDoubles.Add(it2.Value());
it2.Next();
}
// if vmap is not empty the wire is open, let us find the first vertex
if (!vmap.IsEmpty()) {
TopTools_MapIteratorOfMapOfShape itt(vmap); // skl : I change "it" to "itt"
while (itt.Key().Orientation() != TopAbs_FORWARD) {
itt.Next();
if (!itt.More()) break;
}
if (itt.More()) V1 = TopoDS::Vertex(itt.Key());
}
else {
// Modified by Sergey KHROMOV - Mon May 13 12:05:30 2002 Begin
// The wire is infinite Try to find the first vertex. It may be NULL.
if (!anInfEmap.IsEmpty()) {
TopTools_MapIteratorOfMapOfShape itt(anInfEmap);
for (; itt.More(); itt.Next()) {
TopoDS_Edge anEdge = TopoDS::Edge(itt.Key());
TopAbs_Orientation anOri = anEdge.Orientation();
Standard_Real aF;
Standard_Real aL;
BRep_Tool::Range(anEdge, aF, aL);
if ((anOri == TopAbs_FORWARD && aF == -Precision::Infinite()) ||
(anOri == TopAbs_REVERSED && aL == Precision::Infinite())) {
myEdge = anEdge;
myVertex = TopoDS_Vertex();
return;
}
}
}
// Modified by Sergey KHROMOV - Mon May 13 12:05:31 2002 End
// use the first vertex in iterator
it.Initialize(W);
while (it.More()) {
const TopoDS_Edge& E = TopoDS::Edge(it.Value());
TopAbs_Orientation Eori = E.Orientation();
if (Eori == TopAbs_INTERNAL || Eori == TopAbs_EXTERNAL) {
// JYL 10-03-97 : waiting for correct processing
// of INTERNAL/EXTERNAL edges
it.Next();
continue;
}
TopExp::Vertices(E,V1,V2,Standard_True);
break;
}
}
if (V1.IsNull() ) return;
if (!myMap.IsBound(V1)) return;
TopTools_ListOfShape& l = myMap(V1);
myEdge = TopoDS::Edge(l.First());
l.RemoveFirst();
myVertex = TopExp::FirstVertex (myEdge, Standard_True);
}
//=======================================================================
//function : More
//purpose :
//=======================================================================
Standard_Boolean BRepTools_WireExplorer::More()const
{
return !myEdge.IsNull();
}
//=======================================================================
//function : Next
//purpose :
//=======================================================================
void BRepTools_WireExplorer::Next()
{
myVertex = TopExp::LastVertex (myEdge, Standard_True);
if (myVertex.IsNull()) {
myEdge = TopoDS_Edge();
return;
}
if (!myMap.IsBound(myVertex)) {
myEdge = TopoDS_Edge();
return;
}
TopTools_ListOfShape& l = myMap(myVertex);
if (l.IsEmpty()) {
myEdge = TopoDS_Edge();
}
else if (l.Extent() == 1) {
// Modified by Sergey KHROMOV - Fri Jun 21 10:28:01 2002 OCC325 Begin
TopoDS_Vertex aV1;
TopoDS_Vertex aV2;
TopoDS_Edge aNextEdge = TopoDS::Edge(l.First());
TopExp::Vertices(aNextEdge, aV1, aV2, Standard_True);
if (!aV1.IsSame(myVertex)) {
myEdge = TopoDS_Edge();
return;
}
if (!myFace.IsNull() && aV1.IsSame(aV2)) {
Handle(Geom2d_Curve) aPrevPC;
Handle(Geom2d_Curve) aNextPC;
Standard_Real aPar11, aPar12;
Standard_Real aPar21, aPar22;
Standard_Real aPrevPar;
Standard_Real aNextFPar;
Standard_Real aNextLPar;
aPrevPC = BRep_Tool::CurveOnSurface(myEdge, myFace, aPar11, aPar12);
aNextPC = BRep_Tool::CurveOnSurface(aNextEdge, myFace, aPar21, aPar22);
if (aPrevPC.IsNull() || aNextPC.IsNull()) {
myEdge = TopoDS_Edge();
return;
}
if (myEdge.Orientation() == TopAbs_FORWARD)
aPrevPar = aPar12;
else
aPrevPar = aPar11;
if (aNextEdge.Orientation() == TopAbs_FORWARD) {
aNextFPar = aPar21;
aNextLPar = aPar22;
} else {
aNextFPar = aPar22;
aNextLPar = aPar21;
}
gp_Pnt2d aPPrev = aPrevPC->Value(aPrevPar);
gp_Pnt2d aPNextF = aNextPC->Value(aNextFPar);
gp_Pnt2d aPNextL = aNextPC->Value(aNextLPar);
if (aPPrev.SquareDistance(aPNextF) > aPPrev.SquareDistance(aPNextL)) {
myEdge = TopoDS_Edge();
return;
}
}
// Modified by Sergey KHROMOV - Fri Jun 21 11:08:16 2002 End
myEdge = TopoDS::Edge(l.First());
l.Clear();
}
else {
if (myFace.IsNull()) {
// Without Face - try to return edges
// as logically as possible
// At first degenerated edges.
TopoDS_Edge E = myEdge;
if (SelectDegenerated(l,E)) {
myEdge = E;
return;
}
// At second double edges.
E = myEdge;
if (SelectDouble(myDoubles,l,E)) {
myEdge = E;
return;
}
TopTools_ListIteratorOfListOfShape it(l);
Standard_Boolean notfound = Standard_True;
while (it.More()) {
if (!it.Value().IsSame(myEdge)) {
myEdge = TopoDS::Edge(it.Value());
l.Remove(it);
notfound = Standard_False;
break;
}
it.Next();
}
if(notfound) {
myEdge = TopoDS_Edge();
return;
}
}
else
{
// If we have more than one edge attached to the list
// probably wire that we explore contains a loop or loops.
Standard_Real dfFPar = 0., dfLPar = 0.;
Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface (myEdge, myFace, dfFPar, dfLPar);
if(aPCurve.IsNull())
{
myEdge = TopoDS_Edge();
return;
}
// Note: current < myVertex > which is last on < myEdge >
// equals in 2D to following 2D points:
// edge is FORWARD - point with MAX parameter on PCurve;
// edge is REVERSED - point with MIN parameter on PCurve.
// Get 2D point equals to < myVertex > in 2D for current edge.
gp_Pnt2d PRef;
if( myEdge.Orientation() == TopAbs_REVERSED )
aPCurve->D0(dfFPar, PRef);
else
aPCurve->D0(dfLPar, PRef);
// Get next 2D point from current edge's PCurve with parameter
// F + dP (REV) or L - dP (FOR)
Standard_Boolean isrevese = ( myEdge.Orientation() == TopAbs_REVERSED );
Standard_Real dfMPar = GetNextParamOnPC(aPCurve,PRef,dfFPar,dfLPar,myTolU,myTolV,isrevese);
gp_Pnt2d PRefm;
aPCurve->D0(dfMPar, PRefm);
// Get vector from PRef to PRefm
gp_Vec2d anERefDir(PRef,PRefm);
// Search the list of edges looking for the edge having hearest
// 2D point of connected vertex to current one and smallest angle.
// First process all degenerated edges, then - all others.
TopTools_ListIteratorOfListOfShape it;
Standard_Integer k = 1, kMin = 0, iDone = 0;
Standard_Boolean isDegenerated = Standard_True;
Standard_Real dmin = RealLast();
Standard_Real dfMinAngle = 3.0*M_PI, dfCurAngle = 3.0*M_PI;
for(iDone = 0; iDone < 2; iDone++)
{
it.Initialize(l);
while( it.More() )
{
const TopoDS_Edge& E = TopoDS::Edge(it.Value());
if( E.IsSame(myEdge) )
{
it.Next();
k++;
continue;
}
TopoDS_Vertex aVert1, aVert2;
TopExp::Vertices (E, aVert1, aVert2, Standard_True);
if( aVert1.IsNull() || aVert2.IsNull() )
{
it.Next();
k++;
continue;
}
aPCurve = BRep_Tool::CurveOnSurface (E, myFace, dfFPar, dfLPar);
if( aPCurve.IsNull() )
{
it.Next();
k++;
continue;
}
gp_Pnt2d aPEb, aPEe;
if( aVert1.IsSame(aVert2) == isDegenerated )
{
if( E.Orientation() == TopAbs_REVERSED )
aPCurve->D0(dfLPar, aPEb);
else
aPCurve->D0(dfFPar, aPEb);
if( Abs(dfLPar-dfFPar) > Precision::PConfusion() )
{
isrevese = ( E.Orientation() == TopAbs_REVERSED );
isrevese = !isrevese;
Standard_Real aEPm = GetNextParamOnPC(aPCurve,aPEb,dfFPar,dfLPar,myTolU,myTolV,isrevese);
aPCurve->D0 (aEPm, aPEe);
if(aPEb.SquareDistance(aPEe) <= gp::Resolution())
{
//seems to be very short curve
gp_Vec2d aD;
aPCurve->D1(aEPm, aPEe, aD);
if( E.Orientation() == TopAbs_REVERSED )
aPEe.SetXY(aPEb.XY()-aD.XY());
else
aPEe.SetXY(aPEb.XY()+aD.XY());
if(aPEb.SquareDistance(aPEe) <= gp::Resolution())
{
it.Next();
k++;
continue;
}
}
gp_Vec2d anEDir(aPEb, aPEe);
dfCurAngle = Abs( anEDir.Angle(anERefDir) );
}
if( dfCurAngle <= dfMinAngle )
{
Standard_Real d = PRef.SquareDistance(aPEb);
if( d <= Precision::PConfusion() )
d = 0.;
if( Abs(aPEb.X()-PRef.X()) < myTolU && Abs(aPEb.Y()-PRef.Y()) < myTolV )
{
if( d <= dmin )
{
dfMinAngle = dfCurAngle;
kMin = k;
dmin = d;
}
}
}
}
it.Next();
k++;
}// while it
if( kMin == 0 )
{
isDegenerated = Standard_False;
k = 1;
dmin = RealLast();
}
else
break;
}// for iDone
if(kMin == 0)
{
// probably unclosed in 2d space wire
myEdge = TopoDS_Edge();
return;
}
// Selection the edge.
it.Initialize(l);
k = 1;
while( it.More() )
{
if( k == kMin )
{
myEdge = TopoDS::Edge(it.Value());
l.Remove(it);
break;
}
it.Next();
k++;
}
}//else face != NULL && l > 1
}//else l > 1
}
//=======================================================================
//function : Current
//purpose :
//=======================================================================
const TopoDS_Edge& BRepTools_WireExplorer::Current()const
{
return myEdge;
}
//=======================================================================
//function : Orientation
//purpose :
//=======================================================================
TopAbs_Orientation BRepTools_WireExplorer::Orientation() const
{
TopoDS_Iterator it(myEdge,Standard_False);
while (it.More()) {
if (myVertex.IsSame(it.Value()))
return it.Value().Orientation();
it.Next();
}
Standard_NoSuchObject::Raise("BRepTools_WireExplorer::Orientation");
return TopAbs_FORWARD;
}
//=======================================================================
//function : CurrentVertex
//purpose :
//=======================================================================
const TopoDS_Vertex& BRepTools_WireExplorer::CurrentVertex() const
{
return myVertex;
}
//=======================================================================
//function : Clear
//purpose :
//=======================================================================
void BRepTools_WireExplorer::Clear()
{
myMap.Clear();
myDoubles.Clear();
myEdge = TopoDS_Edge();
myFace = TopoDS_Face();
myVertex = TopoDS_Vertex();
}
//=======================================================================
//function : SelectDouble
//purpose :
//=======================================================================
Standard_Boolean SelectDouble(TopTools_MapOfShape& Doubles,
TopTools_ListOfShape& L,
TopoDS_Edge& E)
{
TopTools_ListIteratorOfListOfShape it(L);
for (; it.More(); it.Next()) {
const TopoDS_Shape& CE = it.Value();
if (Doubles.Contains(CE) && (!E.IsSame(CE))) {
E = TopoDS::Edge(CE);
L.Remove(it);
return 1;
}
}
return 0;
}
//=======================================================================
//function : SelectDegenerated
//purpose :
//=======================================================================
Standard_Boolean SelectDegenerated(TopTools_ListOfShape& L,
TopoDS_Edge& E)
{
TopTools_ListIteratorOfListOfShape it(L);
while (it.More()) {
if (!it.Value().IsSame(E)) {
E = TopoDS::Edge(it.Value());
if (BRep_Tool::Degenerated(E)) {
L.Remove(it);
return 1;
}
}
it.Next();
}
return 0;
}
//=======================================================================
//function : GetNextParamOnPC
//purpose :
//=======================================================================
Standard_Real GetNextParamOnPC(const Handle(Geom2d_Curve)& aPC,
const gp_Pnt2d& aPRef,
const Standard_Real& fP,
const Standard_Real& lP,
const Standard_Real& tolU,
const Standard_Real& tolV,
const Standard_Boolean& reverse)
{
Standard_Real result = ( reverse ) ? fP : lP;
Standard_Real dP = Abs( lP - fP ) / 1000.; // was / 16.;
if( reverse )
{
Standard_Real startPar = fP;
Standard_Boolean nextPntOnEdge = Standard_False;
while( !nextPntOnEdge && startPar < lP )
{
gp_Pnt2d pnt;
startPar += dP;
aPC->D0(startPar, pnt);
if( Abs( aPRef.X() - pnt.X() ) < tolU && Abs( aPRef.Y() - pnt.Y() ) < tolV )
continue;
else
{
result = startPar;
nextPntOnEdge = Standard_True;
break;
}
}
if( !nextPntOnEdge )
result = lP;
if( result > lP )
result = lP;
}
else
{
Standard_Real startPar = lP;
Standard_Boolean nextPntOnEdge = Standard_False;
while( !nextPntOnEdge && startPar > fP )
{
gp_Pnt2d pnt;
startPar -= dP;
aPC->D0(startPar, pnt);
if( Abs( aPRef.X() - pnt.X() ) < tolU && Abs( aPRef.Y() - pnt.Y() ) < tolV )
continue;
else
{
result = startPar;
nextPntOnEdge = Standard_True;
break;
}
}
if( !nextPntOnEdge )
result = fP;
if( result < fP )
result = fP;
}
return result;
}