1 // Created on: 1993-01-21
2 // Created by: Remi LEQUETTE
3 // Copyright (c) 1993-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
18 #include <BRep_Tool.hxx>
19 #include <BRepTools.hxx>
20 #include <BRepTools_WireExplorer.hxx>
21 #include <Geom2d_Curve.hxx>
22 #include <Geom_Surface.hxx>
23 #include <GeomAdaptor_Surface.hxx>
24 #include <gp_Pnt2d.hxx>
25 #include <Precision.hxx>
26 #include <Standard_DomainError.hxx>
27 #include <Standard_NoMoreObject.hxx>
28 #include <Standard_NoSuchObject.hxx>
30 #include <TopExp_Explorer.hxx>
32 #include <TopoDS_Edge.hxx>
33 #include <TopoDS_Face.hxx>
34 #include <TopoDS_Iterator.hxx>
35 #include <TopoDS_Vertex.hxx>
36 #include <TopoDS_Wire.hxx>
37 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
38 #include <TopTools_ListIteratorOfListOfShape.hxx>
39 #include <TopTools_ListOfShape.hxx>
40 #include <TopTools_MapIteratorOfMapOfShape.hxx>
41 #include <TopTools_MapOfShape.hxx>
43 //=======================================================================
44 // forward declarations of aux functions
45 //=======================================================================
46 static Standard_Boolean SelectDouble(TopTools_MapOfShape& Doubles,
47 TopTools_ListOfShape& L,
50 static Standard_Boolean SelectDegenerated(TopTools_ListOfShape& L,
53 static Standard_Real GetNextParamOnPC(const Handle(Geom2d_Curve)& aPC,
54 const gp_Pnt2d& aPRef,
55 const Standard_Real& fP,
56 const Standard_Real& lP,
57 const Standard_Real& tolU,
58 const Standard_Real& tolV,
59 const Standard_Boolean& reverse);
61 //=======================================================================
62 //function : BRepTools_WireExplorer
64 //=======================================================================
65 BRepTools_WireExplorer::BRepTools_WireExplorer()
69 //=======================================================================
70 //function : BRepTools_WireExplorer
72 //=======================================================================
73 BRepTools_WireExplorer::BRepTools_WireExplorer(const TopoDS_Wire& W)
75 TopoDS_Face F = TopoDS_Face();
79 //=======================================================================
80 //function : BRepTools_WireExplorer
82 //=======================================================================
83 BRepTools_WireExplorer::BRepTools_WireExplorer(const TopoDS_Wire& W,
89 //=======================================================================
92 //=======================================================================
93 void BRepTools_WireExplorer::Init(const TopoDS_Wire& W)
95 TopoDS_Face F = TopoDS_Face();
99 //=======================================================================
102 //=======================================================================
103 void BRepTools_WireExplorer::Init(const TopoDS_Wire& W,
104 const TopoDS_Face& F)
106 myEdge = TopoDS_Edge();
107 myVertex = TopoDS_Vertex();
115 Standard_Real dfVertToler = 0.;
116 myReverse = Standard_False;
118 if (!myFace.IsNull())
120 BRepTools::Update(myFace);
122 const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(myFace, aL);
123 GeomAdaptor_Surface aGAS(aSurf);
124 TopExp_Explorer anExp(W, TopAbs_VERTEX);
125 for(; anExp.More(); anExp.Next())
127 const TopoDS_Vertex& aV = TopoDS::Vertex(anExp.Current());
128 dfVertToler = Max(BRep_Tool::Tolerance(aV), dfVertToler);
130 myTolU = 2. * aGAS.UResolution(dfVertToler);
131 myTolV = 2. * aGAS.VResolution(dfVertToler);
133 // uresolution for cone with infinite vmin vmax is too small.
134 if(aGAS.GetType() == GeomAbs_Cone)
136 Standard_Real u1, u2, v1, v2;
137 BRepTools::UVBounds(myFace, u1, u2, v1, v2);
140 aGAS.D1(u1, v1, aP, aD1U, aD1V);
141 Standard_Real tol1, tol2, maxtol = .0005*(u2-u1);
142 Standard_Real a = aD1U.Magnitude();
144 if(a <= Precision::Confusion())
147 tol1 = Min(maxtol, dfVertToler/a);
149 aGAS.D1(u1, v2, aP, aD1U, aD1V);
150 a = aD1U.Magnitude();
151 if(a <= Precision::Confusion())
154 tol2 = Min(maxtol, dfVertToler/a);
156 myTolU = 2. * Max(tol1, tol2);
159 if( aGAS.GetType() == GeomAbs_BSplineSurface ||
160 aGAS.GetType() == GeomAbs_BezierSurface )
162 Standard_Real maxTol = Max(myTolU, myTolV);
165 Standard_Real u1, u2, v1, v2;
166 BRepTools::UVBounds(myFace, u1, u2, v1, v2);
167 aGAS.D1((u2 - u1) / 2., (v2 - v1) / 2., aP, aDU, aDV);
168 Standard_Real mod = Sqrt(aDU*aDU + aDV*aDV);
169 if (mod * maxTol / dfVertToler < 1.5)
171 maxTol = 1.5 * dfVertToler / mod;
177 myReverse = (myFace.Orientation() == TopAbs_REVERSED);
180 // map of vertices to know if the wire is open
181 TopTools_MapOfShape vmap;
182 // Modified by Sergey KHROMOV - Mon May 13 11:50:48 2002 Begin
183 // map of infinite edges
184 TopTools_MapOfShape anInfEmap;
185 // Modified by Sergey KHROMOV - Mon May 13 11:50:49 2002 End
189 TopTools_ListOfShape empty;
191 TopoDS_Iterator it(W);
194 const TopoDS_Edge& E = TopoDS::Edge(it.Value());
195 TopAbs_Orientation Eori = E.Orientation();
196 if (Eori == TopAbs_INTERNAL || Eori == TopAbs_EXTERNAL)
201 TopExp::Vertices(E,V1,V2,Standard_True);
205 if( !myMap.IsBound(V1) )
206 myMap.Bind(V1,empty);
209 // add or remove in the vertex map
210 V1.Orientation(TopAbs_FORWARD);
217 V2.Orientation(TopAbs_REVERSED);
222 // Modified by Sergey KHROMOV - Mon May 13 11:52:20 2002 Begin
223 if (V1.IsNull() || V2.IsNull())
225 Standard_Real aF = 0., aL = 0.;
226 BRep_Tool::Range(E, aF, aL);
228 if(Eori == TopAbs_FORWARD)
230 if (aF == -Precision::Infinite())
234 { // Eori == TopAbs_REVERSED
235 if (aL == Precision::Infinite())
239 // Modified by Sergey KHROMOV - Mon May 13 11:52:20 2002 End
243 //Construction of the set of double edges.
244 TopoDS_Iterator it2(W);
245 TopTools_MapOfShape emap;
247 if (!emap.Add(it2.Value()))
248 myDoubles.Add(it2.Value());
252 // if vmap is not empty the wire is open, let us find the first vertex
253 if (!vmap.IsEmpty()) {
254 TopTools_MapIteratorOfMapOfShape itt(vmap); // skl : I change "it" to "itt"
255 while (itt.Key().Orientation() != TopAbs_FORWARD) {
257 if (!itt.More()) break;
259 if (itt.More()) V1 = TopoDS::Vertex(itt.Key());
262 // Modified by Sergey KHROMOV - Mon May 13 12:05:30 2002 Begin
263 // The wire is infinite Try to find the first vertex. It may be NULL.
264 if (!anInfEmap.IsEmpty()) {
265 TopTools_MapIteratorOfMapOfShape itt(anInfEmap);
267 for (; itt.More(); itt.Next()) {
268 TopoDS_Edge anEdge = TopoDS::Edge(itt.Key());
269 TopAbs_Orientation anOri = anEdge.Orientation();
273 BRep_Tool::Range(anEdge, aF, aL);
274 if ((anOri == TopAbs_FORWARD && aF == -Precision::Infinite()) ||
275 (anOri == TopAbs_REVERSED && aL == Precision::Infinite())) {
277 myVertex = TopoDS_Vertex();
283 // Modified by Sergey KHROMOV - Mon May 13 12:05:31 2002 End
286 // use the first vertex in iterator
289 const TopoDS_Edge& E = TopoDS::Edge(it.Value());
290 TopAbs_Orientation Eori = E.Orientation();
291 if (Eori == TopAbs_INTERNAL || Eori == TopAbs_EXTERNAL) {
292 // JYL 10-03-97 : waiting for correct processing
293 // of INTERNAL/EXTERNAL edges
297 TopExp::Vertices(E,V1,V2,Standard_True);
302 if (V1.IsNull() ) return;
303 if (!myMap.IsBound(V1)) return;
305 TopTools_ListOfShape& l = myMap(V1);
306 myEdge = TopoDS::Edge(l.First());
308 myVertex = TopExp::FirstVertex (myEdge, Standard_True);
312 //=======================================================================
315 //=======================================================================
316 Standard_Boolean BRepTools_WireExplorer::More()const
318 return !myEdge.IsNull();
321 //=======================================================================
324 //=======================================================================
325 void BRepTools_WireExplorer::Next()
327 myVertex = TopExp::LastVertex (myEdge, Standard_True);
329 if (myVertex.IsNull()) {
330 myEdge = TopoDS_Edge();
333 if (!myMap.IsBound(myVertex)) {
334 myEdge = TopoDS_Edge();
338 TopTools_ListOfShape& l = myMap(myVertex);
341 myEdge = TopoDS_Edge();
343 else if (l.Extent() == 1) {
344 // Modified by Sergey KHROMOV - Fri Jun 21 10:28:01 2002 OCC325 Begin
347 TopoDS_Edge aNextEdge = TopoDS::Edge(l.First());
349 TopExp::Vertices(aNextEdge, aV1, aV2, Standard_True);
351 if (!aV1.IsSame(myVertex)) {
352 myEdge = TopoDS_Edge();
355 if (!myFace.IsNull() && aV1.IsSame(aV2)) {
356 Handle(Geom2d_Curve) aPrevPC;
357 Handle(Geom2d_Curve) aNextPC;
358 Standard_Real aPar11, aPar12;
359 Standard_Real aPar21, aPar22;
360 Standard_Real aPrevPar;
361 Standard_Real aNextFPar;
362 Standard_Real aNextLPar;
364 aPrevPC = BRep_Tool::CurveOnSurface(myEdge, myFace, aPar11, aPar12);
365 aNextPC = BRep_Tool::CurveOnSurface(aNextEdge, myFace, aPar21, aPar22);
367 if (aPrevPC.IsNull() || aNextPC.IsNull()) {
368 myEdge = TopoDS_Edge();
372 if (myEdge.Orientation() == TopAbs_FORWARD)
377 if (aNextEdge.Orientation() == TopAbs_FORWARD) {
385 gp_Pnt2d aPPrev = aPrevPC->Value(aPrevPar);
386 gp_Pnt2d aPNextF = aNextPC->Value(aNextFPar);
387 gp_Pnt2d aPNextL = aNextPC->Value(aNextLPar);
389 if (aPPrev.SquareDistance(aPNextF) > aPPrev.SquareDistance(aPNextL)) {
390 myEdge = TopoDS_Edge();
394 // Modified by Sergey KHROMOV - Fri Jun 21 11:08:16 2002 End
395 myEdge = TopoDS::Edge(l.First());
399 if (myFace.IsNull()) {
400 // Without Face - try to return edges
401 // as logically as possible
402 // At first degenerated edges.
403 TopoDS_Edge E = myEdge;
404 if (SelectDegenerated(l,E)) {
408 // At second double edges.
410 if (SelectDouble(myDoubles,l,E)) {
415 TopTools_ListIteratorOfListOfShape it(l);
416 Standard_Boolean notfound = Standard_True;
418 if (!it.Value().IsSame(myEdge)) {
419 myEdge = TopoDS::Edge(it.Value());
421 notfound = Standard_False;
428 myEdge = TopoDS_Edge();
435 // If we have more than one edge attached to the list
436 // probably wire that we explore contains a loop or loops.
437 Standard_Real dfFPar = 0., dfLPar = 0.;
438 Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface (myEdge, myFace, dfFPar, dfLPar);
441 myEdge = TopoDS_Edge();
444 // Note: current < myVertex > which is last on < myEdge >
445 // equals in 2D to following 2D points:
446 // edge is FORWARD - point with MAX parameter on PCurve;
447 // edge is REVERSED - point with MIN parameter on PCurve.
449 // Get 2D point equals to < myVertex > in 2D for current edge.
451 if( myEdge.Orientation() == TopAbs_REVERSED )
452 aPCurve->D0(dfFPar, PRef);
454 aPCurve->D0(dfLPar, PRef);
456 // Get next 2D point from current edge's PCurve with parameter
457 // F + dP (REV) or L - dP (FOR)
458 Standard_Boolean isrevese = ( myEdge.Orientation() == TopAbs_REVERSED );
459 Standard_Real dfMPar = GetNextParamOnPC(aPCurve,PRef,dfFPar,dfLPar,myTolU,myTolV,isrevese);
462 aPCurve->D0(dfMPar, PRefm);
463 // Get vector from PRef to PRefm
464 gp_Vec2d anERefDir(PRef,PRefm);
465 // Search the list of edges looking for the edge having hearest
466 // 2D point of connected vertex to current one and smallest angle.
467 // First process all degenerated edges, then - all others.
469 TopTools_ListIteratorOfListOfShape it;
470 Standard_Integer k = 1, kMin = 0, iDone = 0;
471 Standard_Boolean isDegenerated = Standard_True;
472 Standard_Real dmin = RealLast();
473 Standard_Real dfMinAngle = 3.0*M_PI, dfCurAngle = 3.0*M_PI;
475 for(iDone = 0; iDone < 2; iDone++)
480 const TopoDS_Edge& E = TopoDS::Edge(it.Value());
481 if( E.IsSame(myEdge) )
488 TopoDS_Vertex aVert1, aVert2;
489 TopExp::Vertices (E, aVert1, aVert2, Standard_True);
490 if( aVert1.IsNull() || aVert2.IsNull() )
497 aPCurve = BRep_Tool::CurveOnSurface (E, myFace, dfFPar, dfLPar);
498 if( aPCurve.IsNull() )
506 if( aVert1.IsSame(aVert2) == isDegenerated )
508 if( E.Orientation() == TopAbs_REVERSED )
509 aPCurve->D0(dfLPar, aPEb);
511 aPCurve->D0(dfFPar, aPEb);
513 if( Abs(dfLPar-dfFPar) > Precision::PConfusion() )
515 isrevese = ( E.Orientation() == TopAbs_REVERSED );
516 isrevese = !isrevese;
517 Standard_Real aEPm = GetNextParamOnPC(aPCurve,aPEb,dfFPar,dfLPar,myTolU,myTolV,isrevese);
519 aPCurve->D0 (aEPm, aPEe);
520 if(aPEb.SquareDistance(aPEe) <= gp::Resolution())
522 //seems to be very short curve
524 aPCurve->D1(aEPm, aPEe, aD);
525 if( E.Orientation() == TopAbs_REVERSED )
526 aPEe.SetXY(aPEb.XY()-aD.XY());
528 aPEe.SetXY(aPEb.XY()+aD.XY());
530 if(aPEb.SquareDistance(aPEe) <= gp::Resolution())
537 gp_Vec2d anEDir(aPEb, aPEe);
538 dfCurAngle = Abs( anEDir.Angle(anERefDir) );
541 if( dfCurAngle <= dfMinAngle )
543 Standard_Real d = PRef.SquareDistance(aPEb);
544 if( d <= Precision::PConfusion() )
546 if( Abs(aPEb.X()-PRef.X()) < myTolU && Abs(aPEb.Y()-PRef.Y()) < myTolV )
550 dfMinAngle = dfCurAngle;
563 isDegenerated = Standard_False;
573 // probably unclosed in 2d space wire
574 myEdge = TopoDS_Edge();
578 // Selection the edge.
585 myEdge = TopoDS::Edge(it.Value());
592 }//else face != NULL && l > 1
596 //=======================================================================
599 //=======================================================================
600 const TopoDS_Edge& BRepTools_WireExplorer::Current()const
605 //=======================================================================
606 //function : Orientation
608 //=======================================================================
609 TopAbs_Orientation BRepTools_WireExplorer::Orientation() const
611 if (myVertex.IsNull()
615 return TopAbs_FORWARD;
618 TopoDS_Iterator it(myEdge,Standard_False);
620 if (myVertex.IsSame(it.Value()))
621 return it.Value().Orientation();
624 throw Standard_NoSuchObject("BRepTools_WireExplorer::Orientation");
627 //=======================================================================
628 //function : CurrentVertex
630 //=======================================================================
631 const TopoDS_Vertex& BRepTools_WireExplorer::CurrentVertex() const
636 //=======================================================================
639 //=======================================================================
641 void BRepTools_WireExplorer::Clear()
645 myEdge = TopoDS_Edge();
646 myFace = TopoDS_Face();
647 myVertex = TopoDS_Vertex();
651 //=======================================================================
652 //function : SelectDouble
654 //=======================================================================
656 Standard_Boolean SelectDouble(TopTools_MapOfShape& Doubles,
657 TopTools_ListOfShape& L,
660 TopTools_ListIteratorOfListOfShape it(L);
662 for (; it.More(); it.Next()) {
663 const TopoDS_Shape& CE = it.Value();
664 if (Doubles.Contains(CE) && (!E.IsSame(CE))) {
665 E = TopoDS::Edge(CE);
673 //=======================================================================
674 //function : SelectDegenerated
676 //=======================================================================
678 Standard_Boolean SelectDegenerated(TopTools_ListOfShape& L,
681 TopTools_ListIteratorOfListOfShape it(L);
683 if (!it.Value().IsSame(E)) {
684 E = TopoDS::Edge(it.Value());
685 if (BRep_Tool::Degenerated(E)) {
695 //=======================================================================
696 //function : GetNextParamOnPC
698 //=======================================================================
699 Standard_Real GetNextParamOnPC(const Handle(Geom2d_Curve)& aPC,
700 const gp_Pnt2d& aPRef,
701 const Standard_Real& fP,
702 const Standard_Real& lP,
703 const Standard_Real& tolU,
704 const Standard_Real& tolV,
705 const Standard_Boolean& reverse)
707 Standard_Real result = ( reverse ) ? fP : lP;
708 Standard_Real dP = Abs( lP - fP ) / 1000.; // was / 16.;
711 Standard_Real startPar = fP;
712 Standard_Boolean nextPntOnEdge = Standard_False;
713 while( !nextPntOnEdge && startPar < lP )
717 aPC->D0(startPar, pnt);
718 if( Abs( aPRef.X() - pnt.X() ) < tolU && Abs( aPRef.Y() - pnt.Y() ) < tolV )
723 nextPntOnEdge = Standard_True;
736 Standard_Real startPar = lP;
737 Standard_Boolean nextPntOnEdge = Standard_False;
738 while( !nextPntOnEdge && startPar > fP )
742 aPC->D0(startPar, pnt);
743 if( Abs( aPRef.X() - pnt.X() ) < tolU && Abs( aPRef.Y() - pnt.Y() ) < tolV )
748 nextPntOnEdge = Standard_True;