1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13 
14 // pdn 10.12.98: tr9_r0501-ug
15 // pdn 28.12.98: PRO10366 shifting pcurve between two singularities
16 //:k7 abv 5.01.99: USA60022.igs ent 243: FixMissingSeam() improved
17 //:l2 abv 10.01.99: USA60022 7289: corrections for reversed face
18 //gka 11.01.99 file PRO7755.stp #2018: work-around error in BRepLib_MakeFace
19 //:p4 abv, pdn 23.02.99: PRO9234 #15720: call BRepTools::Update() for faces
20 //    rln 03.03.99 S4135: transmission of parameter precision to SA_Surface::NbSingularities
21 //:q5 abv 19.03.99 code improvement
22 //%14 pdn 15.03.99 adding function for fixing null area wires
23 //%15 pdn 20.03.99 code improvement
24 //    abv 09.04.99 S4136: improve tolerance management; remove unused flag Closed
25 //#4  szv          S4163: optimization
26 //    smh 31.01.01 BUC60810 : Case of small wire on face in solid
27 // sln 25.09.2001  checking order of 3d and 2d representation curves
28 // abv 19.10.2001  FixAddNaturalBound improved and extracted as separate fix
29 // skl,pdn 14.05.2002  OCC55 (correction precision for small faces)
30 
31 #include <Bnd_Box.hxx>
32 #include <Bnd_Box2d.hxx>
33 #include <BndLib_Add2dCurve.hxx>
34 #include <BRep_Builder.hxx>
35 #include <BRep_Tool.hxx>
36 #include <BRepBuilderAPI_MakeFace.hxx>
37 #include <BRepBuilderAPI_MakeVertex.hxx>
38 #include <BRepBuilderAPI_MakeWire.hxx>
39 #include <BRepGProp.hxx>
40 #include <BRepTools.hxx>
41 #include <BRepTopAdaptor_FClass2d.hxx>
42 #include <Geom2d_BSplineCurve.hxx>
43 #include <Geom2d_Curve.hxx>
44 #include <Geom2d_Line.hxx>
45 #include <Geom2dAdaptor_Curve.hxx>
46 #include <Geom2dInt_GInter.hxx>
47 #include <Geom_BSplineSurface.hxx>
48 #include <Geom_Circle.hxx>
49 #include <Geom_ConicalSurface.hxx>
50 #include <Geom_Curve.hxx>
51 #include <Geom_RectangularTrimmedSurface.hxx>
52 #include <Geom_SphericalSurface.hxx>
53 #include <Geom_Surface.hxx>
54 #include <Geom_ToroidalSurface.hxx>
55 #include <GeomAdaptor_Surface.hxx>
56 #include <GProp_GProps.hxx>
57 #include <IntRes2d_Domain.hxx>
58 #include <IntRes2d_IntersectionPoint.hxx>
59 #include <IntRes2d_IntersectionSegment.hxx>
60 #include <IntRes2d_Transition.hxx>
61 #include <Message_Msg.hxx>
62 #include <NCollection_Array1.hxx>
63 #include <Precision.hxx>
64 #include <ShapeAnalysis.hxx>
65 #include <ShapeAnalysis_Edge.hxx>
66 #include <ShapeAnalysis_Surface.hxx>
67 #include <ShapeAnalysis_Wire.hxx>
68 #include <ShapeBuild_Edge.hxx>
69 #include <ShapeBuild_ReShape.hxx>
70 #include <ShapeExtend_BasicMsgRegistrator.hxx>
71 #include <ShapeExtend_CompositeSurface.hxx>
72 #include <ShapeExtend_WireData.hxx>
73 #include <ShapeFix.hxx>
74 #include <ShapeFix_ComposeShell.hxx>
75 #include <ShapeFix_DataMapOfShapeBox2d.hxx>
76 #include <ShapeFix_Edge.hxx>
77 #include <ShapeFix_Face.hxx>
78 #include <ShapeFix_IntersectionTool.hxx>
79 #include <ShapeFix_SplitTool.hxx>
80 #include <ShapeFix_Wire.hxx>
81 #include <Standard_ErrorHandler.hxx>
82 #include <Standard_Failure.hxx>
83 #include <Standard_Type.hxx>
84 #include <TColGeom_HArray2OfSurface.hxx>
85 #include <TColgp_SequenceOfPnt2d.hxx>
86 #include <TColStd_MapOfInteger.hxx>
87 #include <TopExp.hxx>
88 #include <TopExp_Explorer.hxx>
89 #include <TopoDS.hxx>
90 #include <TopoDS_Compound.hxx>
91 #include <TopoDS_Edge.hxx>
92 #include <TopoDS_Face.hxx>
93 #include <TopoDS_Iterator.hxx>
94 #include <TopoDS_Shell.hxx>
95 #include <TopoDS_Vertex.hxx>
96 #include <TopoDS_Wire.hxx>
97 #include <TopTools_DataMapOfShapeInteger.hxx>
98 #include <TopTools_DataMapOfShapeListOfShape.hxx>
99 #include <TopTools_DataMapOfShapeShape.hxx>
100 #include <TopTools_IndexedMapOfShape.hxx>
101 #include <TopTools_ListIteratorOfListOfShape.hxx>
102 #include <TopTools_MapOfShape.hxx>
103 #include <TopTools_SequenceOfShape.hxx>
104 
IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Face,ShapeFix_Root)105 IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Face,ShapeFix_Root)
106 
107 #ifdef OCCT_DEBUG
108 #define DEBUG
109 #endif
110 
111 static Standard_Boolean IsSurfaceUVInfinite(const Handle(Geom_Surface)& theSurf)
112 {
113   Standard_Real UMin,UMax,VMin,VMax;
114   theSurf->Bounds(UMin,UMax,VMin,VMax);
115 
116   return (Precision::IsInfinite(UMin) ||
117           Precision::IsInfinite(UMax) ||
118           Precision::IsInfinite(VMin) ||
119           Precision::IsInfinite(VMax)   );
120 }
121 
IsSurfaceUVPeriodic(const Handle (GeomAdaptor_Surface)& theSurf)122 static Standard_Boolean IsSurfaceUVPeriodic(const Handle(GeomAdaptor_Surface)& theSurf)
123 {
124 	return ( (theSurf->IsUPeriodic() && theSurf->IsVPeriodic()) || theSurf->GetType() == GeomAbs_Sphere);
125 }
126 
127 //=======================================================================
128 //function : ShapeFix_Face
129 //purpose  :
130 //=======================================================================
131 
ShapeFix_Face()132 ShapeFix_Face::ShapeFix_Face()
133 {
134   myFwd = Standard_True;
135   myStatus = 0;
136   myFixWire = new ShapeFix_Wire;
137   ClearModes();
138 }
139 
140 //=======================================================================
141 //function : ShapeFix_Face
142 //purpose  :
143 //=======================================================================
144 
ShapeFix_Face(const TopoDS_Face & face)145 ShapeFix_Face::ShapeFix_Face(const TopoDS_Face &face)
146 {
147   myFwd = Standard_True;
148   myStatus = 0;
149   myFixWire = new ShapeFix_Wire;
150   ClearModes();
151   Init( face );
152 }
153 
154 //=======================================================================
155 //function : ClearModes
156 //purpose  :
157 //=======================================================================
158 
ClearModes()159 void ShapeFix_Face::ClearModes()
160 {
161   myFixWireMode              = -1;
162   myFixOrientationMode       = -1;
163   myFixAddNaturalBoundMode   = -1;
164   myFixMissingSeamMode       = -1;
165   myFixSmallAreaWireMode     = -1;
166   myRemoveSmallAreaFaceMode  = -1;
167   myFixIntersectingWiresMode = -1;
168   myFixLoopWiresMode         = -1;
169   myFixSplitFaceMode         = -1;
170   myAutoCorrectPrecisionMode =  1;
171   myFixPeriodicDegenerated   = -1;
172 }
173 
174 //=======================================================================
175 //function : SetMsgRegistrator
176 //purpose  :
177 //=======================================================================
178 
SetMsgRegistrator(const Handle (ShapeExtend_BasicMsgRegistrator)& msgreg)179 void ShapeFix_Face::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg)
180 {
181   ShapeFix_Root::SetMsgRegistrator ( msgreg );
182   myFixWire->SetMsgRegistrator ( msgreg );
183 }
184 
185 //=======================================================================
186 //function : SetPrecision
187 //purpose  :
188 //=======================================================================
189 
SetPrecision(const Standard_Real preci)190 void ShapeFix_Face::SetPrecision (const Standard_Real preci)
191 {
192   ShapeFix_Root::SetPrecision ( preci );
193   myFixWire->SetPrecision ( preci );
194 }
195 
196 //=======================================================================
197 //function : SetMinTolerance
198 //purpose  :
199 //=======================================================================
200 
SetMinTolerance(const Standard_Real mintol)201 void ShapeFix_Face::SetMinTolerance (const Standard_Real mintol)
202 {
203   ShapeFix_Root::SetMinTolerance ( mintol );
204   myFixWire->SetMinTolerance ( mintol );
205 }
206 
207 //=======================================================================
208 //function : SetMaxTolerance
209 //purpose  :
210 //=======================================================================
211 
SetMaxTolerance(const Standard_Real maxtol)212 void ShapeFix_Face::SetMaxTolerance (const Standard_Real maxtol)
213 {
214   ShapeFix_Root::SetMaxTolerance ( maxtol );
215   myFixWire->SetMaxTolerance ( maxtol );
216 }
217 
218 //=======================================================================
219 //function : Init
220 //purpose  :
221 //=======================================================================
222 
Init(const Handle (Geom_Surface)& surf,const Standard_Real preci,const Standard_Boolean fwd)223 void ShapeFix_Face::Init (const Handle(Geom_Surface)& surf,
224 			  const Standard_Real preci, const Standard_Boolean fwd)
225 {
226   myStatus = 0;
227   Handle(ShapeAnalysis_Surface) sas = new ShapeAnalysis_Surface ( surf );
228   Init ( sas, preci, fwd );
229 }
230 
231 //=======================================================================
232 //function : Init
233 //purpose  :
234 //=======================================================================
235 
Init(const Handle (ShapeAnalysis_Surface)& surf,const Standard_Real preci,const Standard_Boolean fwd)236 void ShapeFix_Face::Init (const Handle(ShapeAnalysis_Surface)& surf,
237 			  const Standard_Real preci, const Standard_Boolean fwd)
238 {
239   myStatus = 0;
240   mySurf = surf;
241   SetPrecision ( preci );
242   BRep_Builder B;
243   B.MakeFace ( myFace, mySurf->Surface(), ::Precision::Confusion() );
244   myShape = myFace;
245   myFwd = fwd;
246   if ( !fwd ) myFace.Orientation(TopAbs_REVERSED);
247 }
248 
249 //=======================================================================
250 //function : Init
251 //purpose  :
252 //=======================================================================
253 
Init(const TopoDS_Face & face)254 void ShapeFix_Face::Init (const TopoDS_Face& face)
255 {
256   myStatus = 0;
257   mySurf = new ShapeAnalysis_Surface ( BRep_Tool::Surface (face) );
258   myFwd = ( face.Orientation() != TopAbs_REVERSED );
259   myFace = face;
260   myShape = myFace;
261 //  myFace = TopoDS::Face(face.EmptyCopied());
262 //  for (TopoDS_Iterator ws (face,Standard_False); ws.More(); ws.Next())
263 //    Add (TopoDS::Wire (ws.Value()) );
264 }
265 
266 //=======================================================================
267 //function : Add
268 //purpose  :
269 //=======================================================================
270 
Add(const TopoDS_Wire & wire)271 void ShapeFix_Face::Add (const TopoDS_Wire& wire)
272 {
273   if ( wire.IsNull() ) return;
274   BRep_Builder B;
275   //szv#4:S4163:12Mar99 SGI warns
276   TopoDS_Shape fc = myFace.Oriented(TopAbs_FORWARD); //:l2 abv 10 Jan 99: Oriented()
277   B.Add ( fc, wire );
278 }
279 
280 
281 //=======================================================================
282 //function : SplitWire
283 //purpose  : auxiliary - try to split wire (it is needed if some segments
284 //           were removed in ShapeFix_Wire::FixSelfIntersection() )
285 //=======================================================================
SplitWire(const TopoDS_Face & face,const TopoDS_Wire & wire,TopTools_SequenceOfShape & aResWires)286 static Standard_Boolean SplitWire(const TopoDS_Face &face, const TopoDS_Wire& wire,
287                                   TopTools_SequenceOfShape& aResWires)
288 {
289   TColStd_MapOfInteger UsedEdges;
290   Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
291   Standard_Integer i,j,k;
292   ShapeAnalysis_Edge sae;
293   for(i=1; i<=sewd->NbEdges(); i++) {
294     if(UsedEdges.Contains(i)) continue;
295     TopoDS_Edge E1 = sewd->Edge(i);
296     UsedEdges.Add(i);
297     TopoDS_Vertex V0,V1,V2;
298     V0 = sae.FirstVertex(E1);
299     V1 = sae.LastVertex(E1);
300     Handle(ShapeExtend_WireData) sewd1 = new ShapeExtend_WireData;
301     sewd1->Add(E1);
302     Standard_Boolean IsConnectedEdge = Standard_True;
303     for(j=2; j<=sewd->NbEdges() && IsConnectedEdge; j++) {
304       TopoDS_Edge E2;
305       for(k=2; k<=sewd->NbEdges(); k++) {
306         if(UsedEdges.Contains(k)) continue;
307         E2 = sewd->Edge(k);
308         TopoDS_Vertex V21 = sae.FirstVertex(E2);
309         TopoDS_Vertex V22 = sae.LastVertex(E2);
310         if( sae.FirstVertex(E2).IsSame(V1) ) {
311           sewd1->Add(E2);
312           UsedEdges.Add(k);
313           V1 = sae.LastVertex(E2);
314           break;
315         }
316       }
317       if(k>sewd->NbEdges()) {
318         IsConnectedEdge = Standard_False;
319         break;
320       }
321       if(V1.IsSame(V0)) {
322         //check that V0 and V1 are same in 2d too
323         Standard_Real a1,b1,a2,b2;
324         Handle (Geom2d_Curve) curve1 = BRep_Tool::CurveOnSurface(E1,face,a1,b1);
325         Handle (Geom2d_Curve) curve2 = BRep_Tool::CurveOnSurface(E2,face,a2,b2);
326         gp_Pnt2d v0,v1;
327         if (E1.Orientation() == TopAbs_REVERSED)
328           a1 = b1;
329         if (E2.Orientation() == TopAbs_REVERSED)
330           b2 = a2;
331         curve1->D0(a1,v0);
332         curve2->D0(b2,v1);
333         GeomAdaptor_Surface anAdaptor(BRep_Tool::Surface(face));
334         Standard_Real tol = Max(BRep_Tool::Tolerance(V0),BRep_Tool::Tolerance(V1));
335         Standard_Real maxResolution = 2 * Max ( anAdaptor.UResolution(tol), anAdaptor.VResolution(tol) );
336         if (v0.SquareDistance(v1) < maxResolution) {
337           // new wire is closed, put it into sequence
338           aResWires.Append(sewd1->Wire());
339           break;
340         }
341       }
342     }
343     if(!IsConnectedEdge) {
344       // create new notclosed wire
345       aResWires.Append(sewd1->Wire());
346     }
347     if(UsedEdges.Extent()==sewd->NbEdges()) break;
348   }
349 
350   if(aResWires.Length()>1) {
351 #ifdef OCCT_DEBUG
352     std::cout<<"Wire was split on "<<aResWires.Length()<<" wires"<< std::endl;
353 #endif
354   }
355 
356   return Standard_True;
357 }
358 
359 
360 //=======================================================================
361 //function : Perform
362 //purpose  :
363 //=======================================================================
364 
Perform()365 Standard_Boolean ShapeFix_Face::Perform()
366 {
367   myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
368   myFixWire->SetContext ( Context() );
369   Handle(ShapeFix_Wire) theAdvFixWire = myFixWire;
370   if (theAdvFixWire.IsNull()) return Standard_False;
371 
372   BRep_Builder B;
373   TopoDS_Shape aInitFace = myFace;
374   // perform first part of fixes on wires
375   Standard_Boolean isfixReorder = Standard_False;
376   Standard_Boolean isReplaced = Standard_False;
377 
378   //gka fix in order to avoid lost messages (following OCC21771)
379   TopTools_DataMapOfShapeShape aMapReorderedWires;
380 
381   Standard_Real aSavPreci =  Precision();
382   if ( NeedFix ( myFixWireMode ) ) {
383     theAdvFixWire->SetFace ( myFace );
384 
385     Standard_Integer usFixLackingMode = theAdvFixWire->FixLackingMode();
386     //Standard_Integer usFixNotchedEdgesMode = theAdvFixWire->FixNotchedEdgesMode(); // CR0024983
387     Standard_Integer usFixSelfIntersectionMode = theAdvFixWire->FixSelfIntersectionMode();
388     theAdvFixWire->FixLackingMode() = Standard_False;
389     //theAdvFixWire->FixNotchedEdgesMode() = Standard_False; // CR0024983
390     theAdvFixWire->FixSelfIntersectionMode() = Standard_False;
391 
392     Standard_Boolean fixed = Standard_False;
393     TopoDS_Shape S = myFace;
394     if ( ! Context().IsNull() )
395       S = Context()->Apply ( myFace );
396     TopoDS_Shape emptyCopied = S.EmptyCopied();
397     TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
398     tmpFace.Orientation ( TopAbs_FORWARD );
399 
400     /*
401     // skl 14.05.2002 OCC55 + corrected 03.03.2004
402     Standard_Real dPreci = aSavPreci*aSavPreci;
403     dPreci*=4;
404     Standard_Real newpreci=dPreci;
405     for(TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next()) {
406       TopoDS_Edge edge = TopoDS::Edge ( exp.Current() );
407       Standard_Real first,last;
408       Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge, first, last);
409       if(!c3d.IsNull()) {
410         Bnd_Box bb;
411         bb.Add(c3d->Value(first));
412         bb.Add(c3d->Value(last));
413         bb.Add(c3d->Value((last+first)/2.));
414         Standard_Real x1,x2,y1,y2,z1,z2,size;
415         bb.Get(x1,y1,z1,x2,y2,z2);
416         size = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1);
417         if(size<newpreci) newpreci=size;
418       }
419     }
420     newpreci=sqrt(newpreci)/2.*1.00001;
421     if( aSavPreci > newpreci && newpreci > Precision::Confusion()) {
422       SetPrecision(newpreci);
423       theAdvFixWire->SetPrecision(newpreci);
424     }
425     // end skl 14.05.2002
426     */
427 
428     // skl 29.03.2010 (OCC21623)
429     if( myAutoCorrectPrecisionMode ) {
430       Standard_Real size = ShapeFix::LeastEdgeSize(S);
431       Standard_Real newpreci = Min(aSavPreci,size/2.);
432       newpreci = newpreci*1.00001;
433       if( aSavPreci > newpreci && newpreci > Precision::Confusion()) {
434         SetPrecision(newpreci);
435         theAdvFixWire->SetPrecision(newpreci);
436       }
437     }
438 
439     isfixReorder = Standard_False;
440     for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
441       if(iter.Value().ShapeType() != TopAbs_WIRE) {
442         B.Add ( tmpFace, iter.Value() );
443         continue;
444       }
445       TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
446       theAdvFixWire->Load ( wire );
447       if(theAdvFixWire->NbEdges() == 0) {
448         if(theAdvFixWire->WireData()->NbNonManifoldEdges())
449           B.Add ( tmpFace, wire );
450         else {
451           fixed = Standard_True;
452           myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
453         }
454 	continue;
455       }
456       if ( theAdvFixWire->Perform() ) {
457 	//fixed = Standard_True;
458         isfixReorder =  (theAdvFixWire->StatusReorder(ShapeExtend_DONE) || isfixReorder);
459         fixed = (theAdvFixWire->StatusSmall(ShapeExtend_DONE) ||
460                theAdvFixWire->StatusConnected(ShapeExtend_DONE) ||
461                theAdvFixWire->StatusEdgeCurves(ShapeExtend_DONE) ||
462                theAdvFixWire->StatusNotches(ShapeExtend_DONE) ||  // CR0024983
463                theAdvFixWire->StatusFixTails(ShapeExtend_DONE) ||
464                theAdvFixWire->StatusDegenerated(ShapeExtend_DONE) ||
465                theAdvFixWire->StatusClosed(ShapeExtend_DONE));
466         TopoDS_Wire w = theAdvFixWire->Wire();
467         if(fixed) {
468           if ( ! Context().IsNull() ) Context()->Replace ( wire, w );
469           if(theAdvFixWire->NbEdges() == 0) {
470             myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
471             continue;
472           }
473         }
474         else if(!wire.IsSame(w))
475           aMapReorderedWires.Bind(wire,w);
476 
477         wire = w;
478       }
479       B.Add ( tmpFace, wire );
480       //      if ( theAdvFixWire->Status ( ShapeExtend_FAIL ) )
481       //	myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
482     }
483 
484     theAdvFixWire->FixLackingMode() = usFixLackingMode;
485     //theAdvFixWire->FixNotchedEdgesMode() = usFixNotchedEdgesMode;  // CR0024983
486     theAdvFixWire->FixSelfIntersectionMode() = usFixSelfIntersectionMode;
487     if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
488 
489     if ( fixed ) {
490       //if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
491       if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
492       //myFace = tmpFace;
493       isReplaced = Standard_True;
494     }
495     if(fixed || isfixReorder) {
496       myFace = tmpFace;
497       if (!theAdvFixWire->StatusReorder(ShapeExtend_DONE5)) {
498         myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
499       }
500     }
501   }
502 
503   myResult = myFace;
504   TopoDS_Shape savShape = myFace; //gka BUG 6555
505 
506   // Specific case for conic surfaces
507   if ( NeedFix(myFixPeriodicDegenerated) )
508     this->FixPeriodicDegenerated();
509 
510   // fix missing seam
511   if ( NeedFix ( myFixMissingSeamMode ) ) {
512     if ( FixMissingSeam() ) {
513       myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
514     }
515   }
516 
517   // cycle by all possible faces coming from FixMissingSeam
518   // each face is processed as if it was single
519   TopExp_Explorer exp(myResult,TopAbs_FACE);
520   for ( ; exp.More(); exp.Next() ) {
521     myFace = TopoDS::Face ( exp.Current() );
522     Standard_Boolean NeedCheckSplitWire = Standard_False;
523 
524     // perform second part of fixes on wires
525     if ( NeedFix ( myFixWireMode ) ) {
526       theAdvFixWire->SetFace ( myFace );
527 
528       Standard_Integer usFixSmallMode = theAdvFixWire->FixSmallMode();
529       Standard_Integer usFixConnectedMode = theAdvFixWire->FixConnectedMode();
530       Standard_Integer usFixEdgeCurvesMode =theAdvFixWire->FixEdgeCurvesMode();
531       Standard_Integer usFixDegeneratedMode  = theAdvFixWire->FixDegeneratedMode();
532       theAdvFixWire->FixSmallMode() = Standard_False;
533       theAdvFixWire->FixConnectedMode() = Standard_False;
534       theAdvFixWire->FixEdgeCurvesMode() = Standard_False;
535       theAdvFixWire->FixDegeneratedMode() = Standard_False;
536 
537       Standard_Boolean fixed = Standard_False;
538       TopoDS_Shape S = myFace;
539       if ( ! Context().IsNull() )
540 	S = Context()->Apply ( myFace );
541       TopoDS_Shape emptyCopied = S.EmptyCopied();
542       TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
543       tmpFace.Orientation ( TopAbs_FORWARD );
544       for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
545         if(iter.Value().ShapeType() != TopAbs_WIRE) {
546           B.Add ( tmpFace,iter.Value());
547           continue;
548         }
549 
550 	TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
551 	theAdvFixWire->Load ( wire );
552         if(theAdvFixWire->NbEdges() == 0) {
553           if(theAdvFixWire->WireData()->NbNonManifoldEdges())
554             B.Add ( tmpFace, wire );
555           else {
556             fixed = Standard_True;
557             myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
558           }
559           continue;
560         }
561 	if ( theAdvFixWire->Perform() ) {
562           isfixReorder =  theAdvFixWire->StatusReorder(ShapeExtend_DONE);
563           fixed = (theAdvFixWire->StatusLacking(ShapeExtend_DONE) ||
564             theAdvFixWire->StatusSelfIntersection(ShapeExtend_DONE) ||
565             theAdvFixWire->StatusNotches(ShapeExtend_DONE) ||
566             theAdvFixWire->StatusFixTails(ShapeExtend_DONE));
567 	  TopoDS_Wire w = theAdvFixWire->Wire();
568           if(fixed) {
569             if ( ! Context().IsNull() ) Context()->Replace ( wire, w );
570 
571           }
572           else if(!wire.IsSame(w))
573             aMapReorderedWires.Bind(wire,w);
574 
575           wire = w;
576 	}
577         if(theAdvFixWire->StatusRemovedSegment())
578           NeedCheckSplitWire = Standard_True;
579 
580         //fix for loop of wire
581         TopTools_SequenceOfShape aLoopWires;
582         if(NeedFix ( myFixLoopWiresMode) && FixLoopWire(aLoopWires)) {
583           if (aLoopWires.Length() > 1)
584             SendWarning ( wire, Message_Msg ( "FixAdvFace.FixLoopWire.MSG0" ) );// Wire was split on several wires
585           myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
586           fixed = Standard_True;
587           Standard_Integer k=1;
588           for( ; k <= aLoopWires.Length(); k++)
589             B.Add (tmpFace,aLoopWires.Value(k));
590         }
591         else
592           B.Add ( tmpFace, wire );
593       }
594 
595       theAdvFixWire->FixSmallMode() = usFixSmallMode;
596       theAdvFixWire->FixConnectedMode() = usFixConnectedMode;
597       theAdvFixWire->FixEdgeCurvesMode() = usFixEdgeCurvesMode;
598       theAdvFixWire->FixDegeneratedMode() = usFixDegeneratedMode;
599 
600       if ( fixed ) {
601 	if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
602         if(!isReplaced && !aInitFace.IsSame(myResult) && ! Context().IsNull()) //gka 06.09.04 BUG 6555
603           Context()->Replace(aInitFace,savShape);
604 	if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
605 	myFace = tmpFace;
606 	myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
607       }
608     }
609 
610     if(NeedCheckSplitWire) {
611       // try to split wire - it is needed if some segments were removed
612       // in ShapeFix_Wire::FixSelfIntersection()
613       TopoDS_Shape S = myFace;
614       if ( ! Context().IsNull() )
615         S = Context()->Apply ( myFace );
616       TopoDS_Shape emptyCopied = S.EmptyCopied();
617       TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
618       tmpFace.Orientation ( TopAbs_FORWARD );
619       TopTools_SequenceOfShape aWires;
620       Standard_Integer nbw=0;
621       for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
622         if(iter.Value().ShapeType() != TopAbs_WIRE) {
623           B.Add (tmpFace,iter.Value());
624           continue;
625         }
626         if(iter.Value().Orientation() != TopAbs_FORWARD &&
627            iter.Value().Orientation() != TopAbs_REVERSED) {
628           B.Add (tmpFace,TopoDS::Wire(iter.Value()));
629           continue;
630         }
631         nbw++;
632         TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
633         SplitWire(tmpFace,wire,aWires);
634       }
635       if(nbw<aWires.Length()) {
636         for(Standard_Integer iw=1; iw<=aWires.Length(); iw++)
637           B.Add (tmpFace,aWires.Value(iw));
638         if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
639         myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
640         myFace = tmpFace;
641       }
642     }
643 
644     // fix intersecting wires
645     if(FixWiresTwoCoincEdges())
646       myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
647     if ( NeedFix ( myFixIntersectingWiresMode ) ) {
648       if ( FixIntersectingWires() ) {
649         myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE6 );
650       }
651     }
652 
653     // fix orientation
654     TopTools_DataMapOfShapeListOfShape MapWires;
655     MapWires.Clear();
656     if ( NeedFix ( myFixOrientationMode ) ) {
657       if ( FixOrientation(MapWires) )
658 	myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
659     }
660 
661     BRepTools::Update(myFace);
662 
663     // fix natural bounds
664     Standard_Boolean NeedSplit = Standard_True;
665     if ( NeedFix ( myFixAddNaturalBoundMode ) ) {
666       if ( FixAddNaturalBound() ) {
667         NeedSplit = Standard_False;
668 	myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
669       }
670     }
671 
672     // split face
673     if ( NeedFix ( myFixSplitFaceMode ) && NeedSplit && MapWires.Extent()>1 ) {
674       if ( FixSplitFace(MapWires) )
675         myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
676     }
677 
678   }
679 
680   //return the original preci
681   SetPrecision(aSavPreci);
682   theAdvFixWire->SetPrecision(aSavPreci);
683 
684   // cycle by all possible faces coming from FixAddNaturalBound
685   // each face is processed as if it was single
686   for ( exp.Init(myResult,TopAbs_FACE); exp.More(); exp.Next() ) {
687     myFace = TopoDS::Face ( exp.Current() );
688 
689     // fix small-area wires
690     if ( NeedFix ( myFixSmallAreaWireMode, Standard_False ) )
691     {
692       const Standard_Boolean isRemoveFace = NeedFix( myRemoveSmallAreaFaceMode, Standard_False );
693       if ( FixSmallAreaWire( isRemoveFace ) )
694         myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
695     }
696   }
697 
698   if ( ! Context().IsNull() ) {
699     if(Status ( ShapeExtend_DONE ) && !isReplaced && !aInitFace.IsSame(savShape))
700     {
701       //gka fix in order to avoid lost messages (following OCC21771)
702       if(aMapReorderedWires.Extent())
703       {
704         TopoDS_Iterator aItW(aInitFace,Standard_False);
705         for( ; aItW.More() ; aItW.Next())
706         {
707           TopoDS_Shape aCurW = aItW.Value();
708           while(aMapReorderedWires.IsBound(aCurW))
709           {
710             TopoDS_Shape aFixW = aMapReorderedWires.Find(aCurW);
711             Context()->Replace(aCurW, aFixW);
712             aCurW = aFixW;
713           }
714         }
715 
716       }
717       Context()->Replace(aInitFace, savShape);
718     }
719     myResult = Context()->Apply ( aInitFace ); //gka 06.09.04
720   }
721   else if(!Status ( ShapeExtend_DONE ))
722     myResult = aInitFace;
723 
724   return Status ( ShapeExtend_DONE );
725 }
726 
727 //=======================================================================
728 //function : Auxiliary functions
729 //purpose  :
730 //=======================================================================
731 
732 // Shift all pcurves of edges in the given wire on the given face
733 // to vector <vec>
Shift2dWire(const TopoDS_Wire w,const TopoDS_Face f,const gp_Vec2d vec,const Handle (ShapeAnalysis_Surface)& mySurf,Standard_Boolean recompute3d=Standard_False)734 static void Shift2dWire(const TopoDS_Wire w, const TopoDS_Face f,
735 			const gp_Vec2d vec,
736                         const Handle(ShapeAnalysis_Surface)& mySurf,
737                         Standard_Boolean recompute3d = Standard_False)
738 {
739   gp_Trsf2d tr2d;
740   tr2d.SetTranslation(vec.XY());
741   ShapeAnalysis_Edge sae;
742   ShapeBuild_Edge sbe;
743   BRep_Builder B;
744   for (TopoDS_Iterator ei (w,Standard_False); ei.More(); ei.Next()){
745     TopoDS_Edge edge = TopoDS::Edge(ei.Value());
746     Handle (Geom2d_Curve) C2d;
747     Standard_Real cf, cl;
748     if ( ! sae.PCurve(edge, f, C2d, cf, cl, Standard_True) ) continue;
749     C2d->Transform(tr2d);
750     if ( recompute3d ) {
751       // recompute 3d curve and vertex
752       sbe.RemoveCurve3d ( edge );
753       sbe.BuildCurve3d ( edge );
754       B.UpdateVertex ( sae.FirstVertex(edge), mySurf->Value(C2d->Value(cf)), 0. );
755     }
756   }
757 }
758 
759 // Cut interval from the sequence of intervals
CutInterval(TColgp_SequenceOfPnt2d & intervals,const gp_Pnt2d & toAddI,const Standard_Real period)760 static Standard_Boolean CutInterval (TColgp_SequenceOfPnt2d &intervals,
761                                      const gp_Pnt2d &toAddI,
762                                      const Standard_Real period)
763 {
764   if ( intervals.Length() <=0 ) return Standard_False;
765   for ( Standard_Integer j=0; j <2; j++ ) { // try twice, align to bottom and to top
766     for ( Standard_Integer i=1; i <= intervals.Length(); i++ ) {
767       gp_Pnt2d interval = intervals(i);
768       // ACIS907, OCC921 a054a.sat (face 124)
769       Standard_Real shift = ShapeAnalysis::AdjustByPeriod ( ( j ? toAddI.X() : toAddI.Y() ),
770                                                             0.5*( interval.X() + interval.Y() ),period);
771       gp_Pnt2d toAdd ( toAddI.X() + shift, toAddI.Y() + shift );
772       if ( toAdd.Y() <= interval.X() || toAdd.X() >= interval.Y() ) continue;
773       if ( toAdd.X() > interval.X() ) {
774         if ( toAdd.Y() < interval.Y() ) {
775           intervals.InsertBefore ( i, interval );
776           intervals.ChangeValue(i+1).SetX ( toAdd.Y() ); // i++...
777         }
778         intervals.ChangeValue(i).SetY ( toAdd.X() );
779       }
780       else if ( toAdd.Y() < interval.Y() ) {
781         intervals.ChangeValue(i).SetX ( toAdd.Y() );
782       }
783       else intervals.Remove ( i-- );
784     }
785   }
786   return Standard_True;
787 }
788 
789 // Find middle of the biggest interval
FindBestInterval(TColgp_SequenceOfPnt2d & intervals)790 static Standard_Real FindBestInterval (TColgp_SequenceOfPnt2d &intervals)
791 {
792   Standard_Real shift = 0., max = -1.;
793   for ( Standard_Integer i=1; i <= intervals.Length(); i++ ) {
794     gp_Pnt2d interval = intervals(i);
795     if ( interval.Y() - interval.X() <= max ) continue;
796     max = interval.Y() - interval.X();
797     shift = interval.X() + 0.5 * max;
798   }
799   return shift;
800 }
801 
802 //=======================================================================
803 //function : FixAddNaturalBound
804 //purpose  :
805 //=======================================================================
806 // Detect missing natural boundary on spherical surfaces and add it if
807 // necessary
808 //pdn 981202: add natural bounds if missing (on sphere only)
809 //:abv 28.08.01: rewritten and extended for toruses
810 
FixAddNaturalBound()811 Standard_Boolean ShapeFix_Face::FixAddNaturalBound()
812 {
813   if ( ! Context().IsNull() ) {
814     TopoDS_Shape S = Context()->Apply ( myFace );
815     myFace = TopoDS::Face ( S );
816   }
817 
818   // collect wires in sequence
819   TopTools_SequenceOfShape ws;
820   TopTools_SequenceOfShape vs;
821   TopoDS_Iterator wi (myFace,Standard_False);
822   for ( ; wi.More(); wi.Next()) {
823     if(wi.Value().ShapeType() == TopAbs_WIRE &&
824        (wi.Value().Orientation() == TopAbs_FORWARD || wi.Value().Orientation() == TopAbs_REVERSED))
825       ws.Append (wi.Value());
826     else
827       vs.Append(wi.Value());
828   }
829 
830   // deal with the case of an empty face: just create a new face by a standard tool
831   if (ws.IsEmpty() && !IsSurfaceUVInfinite (mySurf->Surface()))
832   {
833     BRepBuilderAPI_MakeFace aFaceBuilder (mySurf->Surface(), Precision::Confusion());
834 
835     TopoDS_Face aNewFace = aFaceBuilder.Face();
836     aNewFace.Orientation (myFace.Orientation());
837 
838     if ( ! Context().IsNull() )
839       Context()->Replace (myFace, aNewFace);
840 
841     // taking into account orientation
842     myFace = aNewFace;
843 
844     //gka 11.01.99 file PRO7755.stp entity #2018 surface #1895: error BRepLib_MakeFace func IsDegenerated
845     Handle(ShapeFix_Edge) sfe = myFixWire->FixEdgeTool();
846     for (TopExp_Explorer Eed (myFace, TopAbs_EDGE); Eed.More(); Eed.Next()) {
847       TopoDS_Edge edg = TopoDS::Edge (Eed.Current());
848       sfe->FixVertexTolerance(edg, myFace);
849     }
850 
851 //    B.UpdateFace (myFace,myPrecision);
852     SendWarning ( myFace, Message_Msg ( "FixAdvFace.FixOrientation.MSG0" ) );// Face created with natural bounds
853     BRepTools::Update(myFace);
854     myResult = myFace;
855     return Standard_True;
856   }
857 
858   // check if surface is double-closed and fix is needed
859   if ( !IsSurfaceUVPeriodic (mySurf->Adaptor3d()) || ShapeAnalysis::IsOuterBound (myFace) )
860     return Standard_False;
861 
862   // Collect information on free intervals in U and V
863   TColgp_SequenceOfPnt2d intU, intV, centers;
864   Standard_Real SUF, SUL, SVF, SVL;
865   mySurf->Bounds(SUF, SUL, SVF, SVL);
866   intU.Append ( gp_Pnt2d(SUF, SUL) );
867   intV.Append ( gp_Pnt2d(SVF, SVL) );
868   Standard_Integer nb = ws.Length();
869   Standard_Integer i;
870 
871   for ( i=1; i <= nb; i ++) {
872     Standard_Real Umin, Vmin, Umax, Vmax;
873 //     Bnd_Box2d B;
874     TopoDS_Wire aw = TopoDS::Wire (ws.Value(i));
875     // PTV 01.11.2002 ACIS907, OCC921 begin
876 //     BRepTools::AddUVBounds(myFace,aw,B);
877 //     B.Get(Umin, Vmin, Umax, Vmax);
878     TopoDS_Face aWireFace = TopoDS::Face( myFace.EmptyCopied() );
879     BRep_Builder aB;
880     aB.Add( aWireFace, aw );
881     ShapeAnalysis::GetFaceUVBounds(aWireFace, Umin, Umax, Vmin, Vmax);
882 
883     // PTV 01.11.2002 ACIS907, OCC921 end
884     if ( mySurf->IsUClosed() ) CutInterval ( intU, gp_Pnt2d(Umin,Umax), SUL-SUF );
885     if ( mySurf->IsVClosed() ) CutInterval ( intV, gp_Pnt2d(Vmin,Vmax), SVL-SVF );
886     centers.Append ( gp_Pnt2d ( 0.5*(Umin+Umax), 0.5*(Vmin+Vmax) ) );
887   }
888 
889   // find best interval and thus compute shift
890   gp_Pnt2d shift(0.,0.);
891   if ( mySurf->IsUClosed() ) shift.SetX ( FindBestInterval ( intU ) );
892   if ( mySurf->IsVClosed() ) shift.SetY ( FindBestInterval ( intV ) );
893 
894   // Adjust all other wires to be inside outer one
895   gp_Pnt2d center ( shift.X() + 0.5*(SUL-SUF), shift.Y() + 0.5*(SVL-SVF) );
896   for ( i=1; i <= nb; i++ ) {
897     TopoDS_Wire wire = TopoDS::Wire (ws.Value(i));
898     gp_Pnt2d sh(0.,0.);
899     if ( mySurf->IsUClosed() )
900       sh.SetX ( ShapeAnalysis::AdjustByPeriod ( centers(i).X(), center.X(), SUL-SUF ) );
901     if ( mySurf->IsVClosed() )
902       sh.SetY ( ShapeAnalysis::AdjustByPeriod ( centers(i).Y(), center.Y(), SVL-SVF ) );
903     Shift2dWire ( wire, myFace, sh.XY(), mySurf );
904   }
905 
906   // Create naturally bounded surface and add that wire to sequence
907 /* variant 1
908   // Create fictive grid and call ComposeShell
909   Handle(Geom_RectangularTrimmedSurface) RTS =
910     new Geom_RectangularTrimmedSurface ( mySurf->Surface(), SUF+shift.X(), SUL+shift.X(),
911                                          SVF+shift.Y(), SVL+shift.Y() );
912   Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
913   grid->SetValue ( 1, 1, RTS );
914   Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
915   TopLoc_Location L;
916 
917   ShapeFix_ComposeShell CompShell;
918   CompShell.Init ( G, L, myFace, ::Precision::Confusion() );
919   CompShell.ClosedMode() = Standard_True;
920   CompShell.NaturalBoundMode() = Standard_True;
921   CompShell.SetContext( Context() );
922   CompShell.SetMaxTolerance(MaxTolerance());
923   CompShell.Perform();
924   TopoDS_Shape res = CompShell.Result();
925 
926   Context()->Replace ( myFace, res );
927   for (TopExp_Explorer exp ( res, TopAbs_FACE ); exp.More(); exp.Next() ) {
928     myFace = TopoDS::Face ( exp.Current() );
929     BRepTools::Update(myFace); //:p4
930   }
931   myResult = Context()->Apply ( myResult );
932 */
933 /* variant 2 */
934   TopLoc_Location L;
935   Handle(Geom_Surface) surf = BRep_Tool::Surface ( myFace, L );
936   BRepBuilderAPI_MakeFace mf (surf, Precision::Confusion());
937   TopoDS_Face ftmp = mf.Face();
938   ftmp.Location ( L );
939   for (wi.Initialize (ftmp,Standard_False); wi.More(); wi.Next()) {
940     if(wi.Value().ShapeType() != TopAbs_WIRE)
941       continue;
942     TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
943     ws.Append ( wire );
944     if ( shift.XY().Modulus() < ::Precision::PConfusion() ) continue;
945     Shift2dWire ( wire, myFace, shift.XY(), mySurf, Standard_True );
946   }
947 
948   // Fix possible case on sphere when gap contains degenerated edge
949   // and thus has a common part with natural boundary
950   // Such hole should be merged with boundary
951   if ( mySurf->Adaptor3d()->GetType() == GeomAbs_Sphere &&
952        ws.Length() == nb+1 ) {
953     Handle(ShapeExtend_WireData) bnd =
954       new ShapeExtend_WireData ( TopoDS::Wire ( ws.Last() ) );
955     // code to become separate method FixTouchingWires()
956     for ( i=1; i <= nb; i++ ) {
957       Handle(ShapeExtend_WireData) sbwd =
958         new ShapeExtend_WireData ( TopoDS::Wire ( ws.Value(i) ) );
959       for (Standard_Integer j=1; j <= sbwd->NbEdges(); j++ ) {
960         if ( ! BRep_Tool::Degenerated ( sbwd->Edge(j) ) ) continue;
961         // find corresponding place in boundary
962         ShapeAnalysis_Edge sae;
963         TopoDS_Vertex V = sae.FirstVertex ( sbwd->Edge(j) );
964         Standard_Integer k;
965         for ( k=1; k <= bnd->NbEdges(); k++ ) {
966           if ( ! BRep_Tool::Degenerated ( bnd->Edge(k) ) ) continue;
967           if ( BRepTools::Compare ( V, sae.FirstVertex ( bnd->Edge(k) ) ) ) break;
968         }
969         if ( k > bnd->NbEdges() ) continue;
970         // and insert hole to that place
971         BRep_Builder B;
972         B.Degenerated ( sbwd->Edge(j), Standard_False );
973         B.Degenerated ( bnd->Edge(k), Standard_False );
974         sbwd->SetLast ( j );
975         bnd->Add ( sbwd, k+1 );
976         ws.Remove ( i-- );
977         nb--;
978         myFixWire->SetFace ( myFace );
979         myFixWire->Load ( bnd );
980         myFixWire->FixConnected();
981         myFixWire->FixDegenerated();
982         ws.SetValue ( ws.Length(), bnd->Wire() );
983         break;
984       }
985     }
986   }
987 
988   // Create resulting face
989   BRep_Builder B;
990   TopoDS_Shape S = myFace.EmptyCopied();
991   S.Orientation ( TopAbs_FORWARD );
992   for ( i = 1; i <= ws.Length(); i++ ) B.Add ( S, ws.Value(i) );
993   for ( i = 1; i <= vs.Length(); i++ ) B.Add ( S, vs.Value(i) );
994   if ( ! myFwd ) S.Orientation (TopAbs_REVERSED);
995   if ( ! Context().IsNull() ) Context()->Replace ( myFace, S );
996   myFace = TopoDS::Face ( S );
997   BRepTools::Update(myFace);
998 
999 /**/
1000 #ifdef OCCT_DEBUG
1001   std::cout<<"Natural bound on sphere or torus with holes added"<<std::endl; // mise au point !
1002 #endif
1003   SendWarning ( myFace, Message_Msg ( "FixAdvFace.FixOrientation.MSG0" ) );// Face created with natural bounds
1004   return Standard_True;
1005 }
1006 
1007 
1008 //=======================================================================
1009 //function : FixOrientation
1010 //purpose  :
1011 //=======================================================================
1012 
FixOrientation()1013 Standard_Boolean ShapeFix_Face::FixOrientation()
1014 {
1015   TopTools_DataMapOfShapeListOfShape MapWires;
1016   MapWires.Clear();
1017   return FixOrientation(MapWires);
1018 }
1019 
1020 
1021 //=======================================================================
1022 //function : FixOrientation
1023 //purpose  :
1024 //=======================================================================
1025 
FixOrientation(TopTools_DataMapOfShapeListOfShape & MapWires)1026 Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShape &MapWires)
1027 {
1028   Standard_Boolean done = Standard_False;
1029 
1030   if ( ! Context().IsNull() ) {
1031     TopoDS_Shape S = Context()->Apply ( myFace );
1032     myFace = TopoDS::Face ( S );
1033   }
1034   TopTools_SequenceOfShape ws;
1035   TopTools_SequenceOfShape allSubShapes;
1036   // smh: BUC60810 : protection against very small wires (one-edge, null-length)
1037   TopTools_SequenceOfShape VerySmallWires;
1038   for ( TopoDS_Iterator wi (myFace,Standard_False); wi.More(); wi.Next()) {
1039     if(wi.Value().ShapeType() == TopAbs_VERTEX ||
1040        (wi.Value().Orientation() != TopAbs_FORWARD &&
1041          wi.Value().Orientation() != TopAbs_REVERSED)) {
1042       allSubShapes.Append (wi.Value());
1043       //ws.Append (wi.Value());
1044       continue;
1045     }
1046 
1047     TopoDS_Iterator ei (wi.Value(),Standard_False);
1048     TopoDS_Edge anEdge;
1049     Standard_Real length = RealLast();
1050     if ( ei.More() ) {
1051       anEdge = TopoDS::Edge(ei.Value());
1052       ei.Next();
1053       if ( ! ei.More() ) {
1054         length = 0;
1055         Standard_Real First, Last;
1056         Handle(Geom_Curve) c3d;
1057         ShapeAnalysis_Edge sae;
1058         if ( sae.Curve3d(anEdge,c3d,First,Last) ) {
1059           gp_Pnt pntIni = c3d->Value(First);
1060           gp_XYZ prev;
1061           prev = pntIni.XYZ();
1062           Standard_Integer NbControl = 10;
1063           for ( Standard_Integer j = 1; j < NbControl; j++) {
1064             Standard_Real prm = ((NbControl-1-j)*First + j*Last)/(NbControl-1);
1065             gp_Pnt pntCurr = c3d->Value(prm);
1066             gp_XYZ curr = pntCurr.XYZ();
1067             gp_XYZ delta = curr - prev;
1068             length += delta.Modulus();
1069             prev = curr;
1070           }
1071         }
1072       }
1073     }
1074     else length = 0;
1075     if (length > ::Precision::Confusion()) {
1076       ws.Append (wi.Value());
1077       allSubShapes.Append (wi.Value());
1078     }
1079     else VerySmallWires.Append (wi.Value());
1080   }
1081   if ( VerySmallWires.Length() >0 ) done = Standard_True;
1082 
1083   Standard_Integer nb = ws.Length();
1084   Standard_Integer nbAll = allSubShapes.Length();
1085   BRep_Builder B;
1086 
1087   // if no wires, just do nothing
1088   if ( nb <= 0) return Standard_False;
1089   Standard_Integer nbInternal=0;
1090 
1091   Standard_Boolean isAddNaturalBounds = (NeedFix (myFixAddNaturalBoundMode) && IsSurfaceUVPeriodic(mySurf->Adaptor3d()));
1092   TColStd_SequenceOfInteger aSeqReversed;
1093   // if wire is only one, check its orientation
1094   if ( nb == 1 ) {
1095     // skl 12.04.2002 for cases with nbwires>1 (VerySmallWires>1)
1096     // make face with only one wire (ws.Value(1))
1097     TopoDS_Shape dummy = myFace.EmptyCopied();
1098     TopoDS_Face af = TopoDS::Face ( dummy );
1099     af.Orientation ( TopAbs_FORWARD );
1100     B.Add (af,ws.Value(1));
1101 
1102     if ((myFixAddNaturalBoundMode != 1 ||
1103       !IsSurfaceUVPeriodic(mySurf->Adaptor3d())) &&
1104       !ShapeAnalysis::IsOuterBound(af))
1105     {
1106       Handle(ShapeExtend_WireData) sbdw =
1107         new ShapeExtend_WireData(TopoDS::Wire(ws.Value(1)));
1108       sbdw->Reverse(myFace);
1109       ws.SetValue(1, sbdw->Wire());
1110       SendWarning(sbdw->Wire(), Message_Msg("FixAdvFace.FixOrientation.MSG5"));// Wire on face was reversed
1111       done = Standard_True;
1112     }
1113   }
1114   // in case of several wires, perform complex analysis
1115 //  ATTENTION ESSAI
1116 //  Plusieurs wires : orientations relatives
1117 //  Chaque wire doit "contenir" tous les autres
1118 //  Evidemment, en cas de peau de leopard, il peut y avoir probleme
1119   else {
1120 //    On prend chaque wire (NB: pcurves presentes !)
1121 //    En principe on devrait rejeter les wires non fermes (cf couture manque ?)
1122 //    On le classe par rapport aux autres, qui doivent tous etre, soit IN soit
1123 //    OUT. Sinon il y a imbrication -> SDB. Si IN, OK, si OUT on inverse
1124 //      (nb : ici pas myClos donc pas de pb de couture)
1125 //    Si au moins une inversion, il faut refaire la face (cf myRebil)
1126 
1127     //:94 abv 30 Jan 98: calculate parametric precision
1128 
1129 //    GeomAdaptor_Surface& Ads = mySurf->Adaptor3d()->ChangeSurface();
1130 //    Standard_Real toluv = Min ( Ads.UResolution(Precision()), Ads.VResolution(Precision()) );
1131     Standard_Boolean uclosed = mySurf->IsUClosed();
1132     Standard_Boolean vclosed = mySurf->IsVClosed();
1133     Standard_Real SUF, SUL, SVF, SVL;
1134     mySurf->Bounds(SUF, SUL, SVF, SVL);
1135     Standard_Real uRange = SUL - SUF;
1136     Standard_Real vRange = SVL - SVF;
1137 
1138     TopTools_DataMapOfShapeListOfShape MW;
1139     TopTools_DataMapOfShapeInteger SI;
1140     TopTools_MapOfShape MapIntWires;
1141     MW.Clear();
1142     SI.Clear();
1143     MapIntWires.Clear();
1144     Standard_Integer NbOuts=0;
1145     Standard_Integer i;
1146 
1147     NCollection_Array1<Bnd_Box2d> aWireBoxes(1, nb);
1148     Standard_Real uMiddle = 0, vMiddle = 0;
1149     Standard_Boolean isFirst = Standard_True;
1150     //create Bounding boxes for each wire
1151     for ( i = 1; i <= nb; i ++) {
1152       TopoDS_Shape aShape = ws.Value(i);
1153       TopoDS_Wire aWire = TopoDS::Wire (aShape);
1154       Bnd_Box2d aBox;
1155       Standard_Real cf,cl;
1156       TopoDS_Iterator ew (aWire);
1157       for(;ew.More(); ew.Next()) {
1158         TopoDS_Edge ed = TopoDS::Edge (ew.Value());
1159         Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface (ed,myFace,cf,cl);
1160         if (cw.IsNull ())
1161         {
1162           continue;
1163         }
1164         Geom2dAdaptor_Curve gac;
1165         Standard_Real aFirst = cw->FirstParameter();
1166         Standard_Real aLast = cw->LastParameter();
1167         if(cw->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) && (cf < aFirst || cl > aLast)) {
1168           //avoiding problems with segment in Bnd_Box
1169           gac.Load(cw);
1170         }
1171        else
1172          gac.Load(cw,cf,cl);
1173        BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),aBox);
1174       }
1175 
1176       Standard_Real aXMin, aXMax, aYMin, aYMax;
1177       aBox.Get(aXMin, aYMin, aXMax, aYMax);
1178       if (isFirst) {
1179         isFirst = Standard_False;
1180         uMiddle = (aXMin + aXMax) * 0.5;
1181         vMiddle = (aYMin + aYMax) * 0.5;
1182       }
1183       else {
1184         Standard_Real xShift = 0, yShift = 0;
1185         if ( mySurf->IsUClosed() )
1186           xShift = ShapeAnalysis::AdjustByPeriod ( 0.5*(aXMin + aXMax), uMiddle, uRange );
1187         if ( mySurf->IsVClosed() )
1188           yShift = ShapeAnalysis::AdjustByPeriod ( 0.5*(aYMin + aYMax), vMiddle, vRange ) ;
1189         aBox.Update(aXMin + xShift, aYMin + yShift, aXMax + xShift, aYMax + yShift);
1190       }
1191       aWireBoxes.ChangeValue(i) = aBox;
1192     }
1193 
1194     for ( i = 1; i <= nb; i ++) {
1195       TopoDS_Shape asw = ws.Value(i);
1196       TopoDS_Wire aw = TopoDS::Wire (asw);
1197       Bnd_Box2d aBox1 = aWireBoxes.Value(i);
1198       TopoDS_Shape dummy = myFace.EmptyCopied();
1199       TopoDS_Face af = TopoDS::Face ( dummy );
1200 //      B.MakeFace (af,mySurf->Surface(),::Precision::Confusion());
1201       af.Orientation ( TopAbs_FORWARD );
1202       B.Add (af,aw);
1203       // PTV OCC945 06.11.2002 files ie_exhaust-A.stp (entities 3782,  3787)
1204       // tolerance is too big. It is seems that to identify placement of 2d point
1205       // it is enough Precision::PConfusion(), cause wea re know that 2d point in TopAbs_ON
1206       // BRepTopAdaptor_FClass2d clas (af,toluv);
1207       Standard_Boolean CheckShift = Standard_True;
1208       BRepTopAdaptor_FClass2d clas (af,::Precision::PConfusion());
1209       TopAbs_State sta = TopAbs_OUT;
1210       TopAbs_State staout = clas.PerformInfinitePoint();
1211       TopTools_ListOfShape IntWires;
1212       Standard_Integer aWireIt = 0;
1213       for ( Standard_Integer j = 1; j <= nbAll; j ++) {
1214         aWireIt++;
1215         //if(i==j) continue;
1216         TopoDS_Shape aSh2 = allSubShapes.Value(j);
1217         if(aw == aSh2)
1218           continue;
1219         TopAbs_State stb = TopAbs_UNKNOWN;
1220         if(aSh2.ShapeType() == TopAbs_VERTEX) {
1221           aWireIt--;
1222           gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(aSh2));
1223           gp_Pnt2d p2d = mySurf->ValueOfUV(aP,Precision::Confusion());
1224           stb = clas.Perform (p2d,Standard_False);
1225           if(stb == staout && (uclosed || vclosed)) {
1226             gp_Pnt2d p2d1;
1227             if(uclosed) {
1228               p2d1.SetCoord(p2d.X()+uRange, p2d.Y());
1229               stb = clas.Perform (p2d1,Standard_False);
1230 
1231             }
1232             if(stb == staout && vclosed) {
1233               p2d1.SetCoord(p2d.X(), p2d.Y()+ vRange);
1234               stb = clas.Perform (p2d1,Standard_False);
1235             }
1236           }
1237         }
1238         else if (aSh2.ShapeType() == TopAbs_WIRE) {
1239           CheckShift = Standard_True;
1240           TopoDS_Wire bw = TopoDS::Wire (aSh2);
1241           //Standard_Integer numin =0;
1242           Bnd_Box2d aBox2 = aWireBoxes.Value(aWireIt);
1243           if (aBox2.IsOut(aBox1))
1244             continue;
1245 
1246           TopoDS_Iterator ew (bw);
1247           for(;ew.More(); ew.Next()) {
1248             TopoDS_Edge ed = TopoDS::Edge (ew.Value());
1249             Standard_Real cf,cl;
1250             Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface (ed,myFace,cf,cl);
1251             if (cw.IsNull()) continue;
1252             gp_Pnt2d unp = cw->Value ((cf+cl)/2.);
1253             TopAbs_State ste = clas.Perform (unp,Standard_False);
1254             if( ste==TopAbs_OUT || ste==TopAbs_IN ) {
1255               if(stb==TopAbs_UNKNOWN) {
1256                 stb = ste;
1257               }
1258               else {
1259                 if(!(stb==ste)) {
1260                   sta = TopAbs_UNKNOWN;
1261                   SI.Bind(aw,0);
1262                   j=nb;
1263                   break;
1264                 }
1265               }
1266             }
1267 
1268             Standard_Boolean found = Standard_False;
1269             gp_Pnt2d unp1;
1270             if( stb == staout && CheckShift ) {
1271               CheckShift = Standard_False;
1272               if(uclosed) {
1273                 unp1.SetCoord(unp.X()+uRange, unp.Y());
1274                 found = (staout != clas.Perform (unp1,Standard_False));
1275                 if(!found) {
1276                   unp1.SetX(unp.X()-uRange);
1277                   found = (staout != clas.Perform (unp1,Standard_False));
1278                 }
1279               }
1280               if(vclosed&&!found) {
1281                 unp1.SetCoord(unp.X(), unp.Y()+vRange);
1282                 found = (staout != clas.Perform (unp1,Standard_False));
1283                 if(!found) {
1284                   unp1.SetY(unp.Y()-vRange);
1285                   found = (staout != clas.Perform (unp1,Standard_False));
1286                 }
1287               }
1288               // Additional check of diagonal steps for toroidal surfaces
1289               if (!found && uclosed && vclosed)
1290               {
1291                 for (Standard_Real dX = -1.0; dX <= 1.0 && !found; dX += 2.0)
1292                   for (Standard_Real dY = -1.0; dY <= 1.0 && !found; dY += 2.0)
1293                   {
1294                     unp1.SetCoord(unp.X() + uRange * dX, unp.Y() + vRange * dY);
1295                     found = (staout != clas.Perform(unp1, Standard_False));
1296                   }
1297               }
1298             }
1299             if(found) {
1300               if(stb==TopAbs_IN) stb = TopAbs_OUT;
1301               else stb = TopAbs_IN;
1302               Shift2dWire(bw,myFace,unp1.XY()-unp.XY(), mySurf);
1303             }
1304           }
1305         }
1306         if(stb==staout) {
1307           sta = TopAbs_IN;
1308         }
1309         else {
1310           IntWires.Append(aSh2);
1311           MapIntWires.Add(aSh2);
1312         }
1313       }
1314 
1315       if (sta == TopAbs_UNKNOWN) {    // ERREUR
1316         SendWarning ( aw, Message_Msg ( "FixAdvFace.FixOrientation.MSG11" ) );// Cannot orient wire
1317       }
1318       else {
1319         MW.Bind(aw,IntWires);
1320         if(sta==TopAbs_OUT) {
1321           NbOuts++;
1322           if(staout==TopAbs_IN ) {
1323             // wire is OUT but InfinitePoint is IN => need to reverse
1324             ShapeExtend_WireData sewd (aw);
1325             sewd.Reverse(myFace);
1326             ws.SetValue (i,sewd.Wire());
1327             SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1328             aSeqReversed.Append(i);
1329             done = Standard_True;
1330             SI.Bind(ws.Value(i),1);
1331             MapWires.Bind(ws.Value(i),IntWires);
1332           }
1333           else {
1334             SI.Bind(aw,1);
1335             MapWires.Bind(aw,IntWires);
1336           }
1337         }
1338         else {
1339           if(staout==TopAbs_OUT) SI.Bind(aw,2);
1340           else SI.Bind(aw,3);
1341         }
1342       }
1343 
1344     }
1345 
1346     for(i=1; i<=nb; i++) {
1347       TopoDS_Wire aw = TopoDS::Wire (ws.Value(i));
1348       Standard_Integer tmpi = SI.Find(aw);
1349       if(tmpi>1) {
1350         if(!MapIntWires.Contains(aw)) {
1351           NbOuts++;
1352           const TopTools_ListOfShape& IW = MW.Find(aw);
1353           if(tmpi==3) {
1354             // wire is OUT but InfinitePoint is IN => need to reverse
1355             ShapeExtend_WireData sewd (aw);
1356             sewd.Reverse(myFace);
1357             ws.SetValue (i,sewd.Wire());
1358             SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1359             aSeqReversed.Append(i);
1360             done = Standard_True;
1361             MapWires.Bind(ws.Value(i),IW);
1362           }
1363           else MapWires.Bind(aw,IW);
1364         }
1365         else {
1366           if(tmpi==2) {
1367             // wire is IN but InfinitePoint is OUT => need to reverse
1368             ShapeExtend_WireData sewd (aw);
1369             sewd.Reverse(myFace);
1370             ws.SetValue (i,sewd.Wire());
1371             SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1372             aSeqReversed.Append(i);
1373             done = Standard_True;
1374           }
1375         }
1376       }
1377     }
1378 
1379   }
1380 
1381   //done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal <nb))));
1382   if(isAddNaturalBounds && nb == aSeqReversed.Length())
1383     done = Standard_False;
1384   else
1385     done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal <nb))));
1386   //    Faut-il reconstruire ? si myRebil est mis
1387   if ( done ) {
1388     TopoDS_Shape S = myFace.EmptyCopied();
1389     S.Orientation ( TopAbs_FORWARD );
1390     Standard_Integer i = 1;
1391     for ( ; i <= nb; i++ )
1392       B.Add ( S, ws.Value(i) );
1393 
1394     if(nb < nbAll) {
1395       for( i =1; i <= nbAll;i++) {
1396         TopoDS_Shape aS2 = allSubShapes.Value(i);
1397         if(aS2.ShapeType() != TopAbs_WIRE ||
1398            (aS2.Orientation() != TopAbs_FORWARD && aS2.Orientation() != TopAbs_REVERSED))
1399           B.Add ( S,aS2);
1400       }
1401     }
1402 
1403     if ( ! myFwd ) S.Orientation (TopAbs_REVERSED);
1404     if ( ! Context().IsNull() ) Context()->Replace ( myFace, S );
1405     myFace = TopoDS::Face ( S );
1406     BRepTools::Update(myFace);
1407     Standard_Integer k =1;
1408     for( ; k <= aSeqReversed.Length(); k++ )
1409     {
1410 #ifdef OCCT_DEBUG
1411       std::cout<<"Wire no "<<aSeqReversed.Value(k)<<" of "<<nb<<" reversed"<<std::endl; // mise au point !
1412 #endif
1413     }
1414 
1415   }
1416   return done;
1417 }
1418 
1419 
1420 //=======================================================================
1421 //function : CheckWire
1422 //purpose  : auxiliary for FixMissingSeam
1423 //=======================================================================
1424 //:i7 abv 18 Sep 98: ProSTEP TR9 r0501-ug.stp: algorithm of fixing missing seam changed
1425 // test whether the wire is opened on period of periodical surface
CheckWire(const TopoDS_Wire & wire,const TopoDS_Face & face,const Standard_Real dU,const Standard_Real dV,Standard_Integer & isuopen,Standard_Integer & isvopen,Standard_Boolean & isDeg)1426 static Standard_Boolean CheckWire (const TopoDS_Wire &wire,
1427                                    const TopoDS_Face &face,
1428                                    const Standard_Real dU,
1429                                    const Standard_Real dV,
1430                                    Standard_Integer &isuopen,
1431                                    Standard_Integer &isvopen,
1432                                    Standard_Boolean &isDeg)
1433 {
1434   gp_XY vec;
1435   vec.SetX(0);
1436   vec.SetY(0);
1437   ShapeAnalysis_Edge sae;
1438 
1439   isuopen = isvopen = 0;
1440   isDeg = Standard_True;
1441   for ( TopoDS_Iterator ed(wire); ed.More(); ed.Next() ) {
1442     TopoDS_Edge edge = TopoDS::Edge ( ed.Value() );
1443     if ( ! BRep_Tool::Degenerated ( edge ) ) isDeg = Standard_False;
1444     Handle(Geom2d_Curve) c2d;
1445     Standard_Real f, l;
1446     if ( ! sae.PCurve ( edge, face, c2d, f, l, Standard_True ) )
1447       return Standard_False;
1448     vec += c2d->Value(l).XY() - c2d->Value(f).XY();
1449   }
1450 
1451   Standard_Real aDelta = Abs(vec.X())-dU;
1452   if(Abs(aDelta) < 0.1*dU)
1453   {
1454     if(vec.X() > 0.0)
1455     {
1456       isuopen = 1;
1457     }
1458     else
1459     {
1460       isuopen = -1;
1461     }
1462   }
1463   else
1464   {
1465     isuopen = 0;
1466   }
1467 
1468   aDelta = Abs(vec.Y())-dV;
1469   if(Abs(aDelta) < 0.1*dV)
1470   {
1471     if(vec.Y() > 0.0)
1472     {
1473       isvopen = 1;
1474     }
1475     else
1476     {
1477       isvopen = -1;
1478     }
1479   }
1480   else
1481   {
1482     isvopen = 0;
1483   }
1484 
1485   return isuopen || isvopen;
1486 }
1487 
1488 //=======================================================================
1489 //function : FixMissingSeam
1490 //purpose  :
1491 //=======================================================================
FixMissingSeam()1492 Standard_Boolean ShapeFix_Face::FixMissingSeam()
1493 {
1494   Standard_Boolean uclosed = mySurf->IsUClosed();
1495   Standard_Boolean vclosed = mySurf->IsVClosed();
1496 
1497   if ( ! uclosed && ! vclosed ) return Standard_False;
1498 
1499   if ( ! Context().IsNull() ) {
1500     TopoDS_Shape S = Context()->Apply ( myFace );
1501     myFace = TopoDS::Face ( S );
1502   }
1503 
1504   //%pdn: surface should be made periodic before (see ShapeCustom_Surface)!
1505   if (mySurf->Surface()->IsKind(STANDARD_TYPE (Geom_BSplineSurface))) {
1506     Handle (Geom_BSplineSurface) BSpl = Handle (Geom_BSplineSurface)::DownCast (mySurf->Surface());
1507     if (!BSpl->IsUPeriodic() && !BSpl->IsVPeriodic())
1508       return Standard_False;
1509   }
1510 
1511   Standard_Real URange, VRange, SUF, SUL, SVF, SVL;
1512   mySurf->Bounds ( SUF, SUL, SVF, SVL );
1513   Standard_Real fU1,fU2,fV1,fV2;
1514   BRepTools::UVBounds(myFace,fU1,fU2,fV1,fV2);
1515 
1516   //pdn OCC55 fix to faces without the wires to avoid identical first and last parameters
1517   if ( ::Precision::IsInfinite ( SUF ) || ::Precision::IsInfinite ( SUL ) ) {
1518     if ( ::Precision::IsInfinite ( SUF ) ) SUF = fU1;
1519     if ( ::Precision::IsInfinite ( SUL ) ) SUL = fU2;
1520     if(Abs(SUL-SUF) < ::Precision::PConfusion()) {
1521       if ( ::Precision::IsInfinite ( SUF ) ) SUF-=1000.;
1522       else SUL+=1000.;
1523     }
1524   }
1525   if ( ::Precision::IsInfinite ( SVF ) || ::Precision::IsInfinite ( SVL ) ) {
1526     if ( ::Precision::IsInfinite ( SVF ) ) SVF = fV1;
1527     if ( ::Precision::IsInfinite ( SVL ) ) SVL = fV2;
1528     if(Abs(SVL-SVF) < ::Precision::PConfusion()) {
1529       if ( ::Precision::IsInfinite ( SVF ) ) SVF-=1000.;
1530       else SVL+=1000.;
1531     }
1532   }
1533 
1534   URange = Min(Abs (SUL - SUF), Precision::Infinite());
1535   VRange = Min(Abs(SVL - SVF), Precision::Infinite());
1536 //  Standard_Real UTol = 0.2 * URange, VTol = 0.2 * VRange;
1537   Standard_Integer ismodeu = 0, ismodev = 0; //szv#4:S4163:12Mar99 was Boolean
1538   Standard_Integer isdeg1=0, isdeg2=0;
1539 
1540   TopTools_SequenceOfShape ws;
1541   TopTools_SequenceOfShape aSeqNonManif;
1542   for ( TopoDS_Iterator wi(myFace,Standard_False); wi.More(); wi.Next() ) {
1543     if(wi.Value().ShapeType() != TopAbs_WIRE ||
1544        (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) {
1545       aSeqNonManif.Append(wi.Value());
1546       continue;
1547     }
1548     ws.Append ( wi.Value() );
1549   }
1550 
1551   TopoDS_Wire w1, w2;
1552   Standard_Integer i;
1553   for ( i=1; i <= ws.Length(); i++ ) {
1554     TopoDS_Wire wire = TopoDS::Wire ( ws.Value(i) );
1555     Standard_Integer isuopen, isvopen;
1556     Standard_Boolean isdeg;
1557     if ( ! CheckWire ( wire, myFace, URange, VRange, isuopen, isvopen, isdeg ) )
1558       continue;
1559     if ( w1.IsNull() ) { w1 = wire; ismodeu = isuopen; ismodev = isvopen; isdeg1 = isdeg ? i : 0; }
1560     else if ( w2.IsNull() ) {
1561       if ( ismodeu == -isuopen && ismodev == -isvopen ) { w2 = wire; isdeg2 = isdeg ? i : 0; }
1562       else if ( ismodeu == isuopen && ismodev == isvopen ) {
1563         w2 = wire;
1564         isdeg2 = isdeg;
1565         //:abv 29.08.01: If wires are contraversal, reverse one of them
1566         // If first one is single degenerated edge, reverse it; else second
1567         if ( isdeg1 ) {
1568           w1.Reverse();
1569           ismodeu = -ismodeu;
1570           ismodev = -ismodev;
1571         }
1572         else {
1573           w2.Reverse();
1574 #ifdef OCCT_DEBUG
1575           if ( ! isdeg2 ) std::cout << "Warning: ShapeFix_Face::FixMissingSeam(): wire reversed" << std::endl;
1576 #endif
1577         }
1578       }
1579 #ifdef OCCT_DEBUG
1580       else std::cout << "Warning: ShapeFix_Face::FixMissingSeam(): incompatible open wires" << std::endl;
1581 #endif
1582     }
1583 //    else return Standard_False; //  abort
1584     else {
1585 #ifdef OCCT_DEBUG
1586       std::cout << "Warning: ShapeFix_Face::FixMissingSeam(): more than two open wires detected!" << std::endl;
1587 #endif
1588       //:abv 30.08.09: if more than one open wires and more than two of them are
1589       // completely degenerated, remove any of them
1590       if ( isdeg || isdeg1 || isdeg2 ) {
1591         ws.Remove ( isdeg ? i : isdeg2 ? isdeg2 : isdeg1 );
1592         w1.Nullify();
1593         w2.Nullify();
1594         i = 0;
1595 #ifdef OCCT_DEBUG
1596         std::cout << "Warning: ShapeFix_Face::FixMissingSeam(): open degenerated wire removed" << std::endl;
1597 #endif
1598         continue;
1599       }
1600     }
1601   }
1602 
1603   BRep_Builder B;
1604   if ( w1.IsNull() ) return Standard_False;
1605   else if ( w2.IsNull()) {
1606     // For spheres and BSpline cone-like surfaces(bug 24055):
1607     // If only one of wires limiting face on surface is open in 2d,
1608     // this may means that degenerated edge should be added, and
1609     // then usual procedure applied
1610     gp_Pnt2d p;
1611     gp_Dir2d d;
1612     Standard_Real aRange;
1613 
1614     if ( ismodeu && mySurf->Surface()->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ) {
1615       p.SetCoord ( ( ismodeu < 0 ? 0. : 2.*M_PI ), ismodeu * 0.5 * M_PI );
1616       Standard_Real aXCoord = -ismodeu;
1617       d.SetCoord ( aXCoord, 0.);
1618       aRange = 2.*M_PI;
1619     }
1620     else if ( ismodev && mySurf->Surface()->IsKind(STANDARD_TYPE(Geom_BSplineSurface))) {
1621       Standard_Real uCoord;
1622       if (mySurf->Value(SUF, SVF).Distance(mySurf->Value(SUF, (SVF + SVL) / 2)) < ::Precision::Confusion())
1623         uCoord = SUF;
1624       else if (mySurf->Value(SUL, SVF).Distance(mySurf->Value(SUL, (SVF + SVL) / 2)) < ::Precision::Confusion())
1625         uCoord = SUL;
1626       else return Standard_False;
1627 
1628       p.SetCoord ( uCoord, ( ismodev < 0 ? 0. : VRange ) );
1629       d.SetCoord ( 0., -ismodev);
1630       aRange = VRange;
1631     }
1632     else if ( ismodeu && mySurf->Surface()->IsKind(STANDARD_TYPE(Geom_BSplineSurface))) {
1633       Standard_Real vCoord;
1634       if (mySurf->Value(SUF, SVF).Distance(mySurf->Value((SUF + SUL) / 2, SVF)) < ::Precision::Confusion())
1635         vCoord = SVF;
1636       else if (mySurf->Value(SUL, SVL).Distance(mySurf->Value((SUF + SUL) / 2, SVL)) < ::Precision::Confusion())
1637         vCoord = SVL;
1638       else return Standard_False;
1639 
1640       p.SetCoord ( ( ismodeu < 0 ? 0. : URange ), vCoord );
1641       Standard_Real aXCoord = -ismodeu;
1642       d.SetCoord ( aXCoord, 0.);
1643       aRange = URange;
1644     }
1645     else return Standard_False;
1646 
1647     Handle(Geom2d_Line) line = new Geom2d_Line ( p, d );
1648     TopoDS_Edge edge;
1649     B.MakeEdge ( edge );
1650     B.Degenerated ( edge, Standard_True );
1651     B.UpdateEdge ( edge, line, myFace, ::Precision::Confusion() );
1652     B.Range ( edge, myFace, 0., aRange );
1653     TopoDS_Vertex V;
1654     B.MakeVertex ( V, mySurf->Value ( p.X(), p.Y() ), ::Precision::Confusion() );
1655     V.Orientation(TopAbs_FORWARD);
1656     B.Add(edge,V);
1657     V.Orientation(TopAbs_REVERSED);
1658     B.Add(edge,V);
1659     B.MakeWire ( w2 );
1660     B.Add ( w2, edge );
1661     ws.Append ( w2 );
1662   }
1663 
1664   // Check consistency of orientations of the two wires that need to be connected by a seam
1665   Standard_Real uf=SUF, vf=SVF;
1666   Standard_Integer coord = ( ismodeu ? 1 : 0 );
1667   Standard_Integer isneg = ( ismodeu ? ismodeu : -ismodev );
1668   Standard_Real period = ( ismodeu ? URange : VRange );
1669   TopoDS_Shape S;
1670   Standard_Real m1[2][2], m2[2][2];
1671   S = myFace.EmptyCopied();
1672   B.Add ( S, w1 );
1673   ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m1[0][0], m1[0][1], m1[1][0], m1[1][1]);
1674   S = myFace.EmptyCopied();
1675   B.Add ( S, w2 );
1676   ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m2[0][0], m2[0][1], m2[1][0], m2[1][1]);
1677 
1678   // For the case when surface is closed only in one direction it is necessary to check
1679   // validity of orientation of the open wires in parametric space.
1680   // In case of U closed surface wire with minimal V coordinate should be directed in positive direction by U
1681   // In case of V closed surface wire with minimal U coordinate should be directed in negative direction by V
1682   if (!vclosed || !uclosed)
1683   {
1684     Standard_Real deltaOther = 0.5 * (m2[coord][0] + m2[coord][1]) - 0.5 * (m1[coord][0] + m1[coord][1]);
1685     if (deltaOther  * isneg < 0)
1686     {
1687       w1.Reverse();
1688       w2.Reverse();
1689     }
1690   }
1691 
1692   // sort original wires
1693   Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
1694   sfw->SetFace ( myFace );
1695   sfw->SetPrecision ( Precision() );
1696   Handle(ShapeExtend_WireData) wd1 = new ShapeExtend_WireData ( w1 );
1697   Handle(ShapeExtend_WireData) wd2 = new ShapeExtend_WireData ( w2 );
1698   sfw->Load ( wd1 );
1699   sfw->FixReorder();
1700   sfw->Load ( wd2 );
1701   sfw->FixReorder();
1702   TopoDS_Wire w11 = wd1->Wire();
1703   TopoDS_Wire w21 = wd2->Wire();
1704 
1705   //:abv 29.08.01: reconstruct face taking into account reversing
1706   TopoDS_Shape dummy = myFace.EmptyCopied();
1707   TopoDS_Face tmpF = TopoDS::Face ( dummy );
1708   tmpF.Orientation ( TopAbs_FORWARD );
1709   for ( i=1; i <= ws.Length(); i++ ) {
1710     TopoDS_Wire wire = TopoDS::Wire ( ws.Value(i) );
1711     if ( wire.IsSame ( w1 ) ) wire = w11;
1712     else if ( wire.IsSame ( w2 ) ) wire = w21;
1713     else
1714     {
1715       // other wires (not boundary) are considered as holes; make sure to have them oriented accordingly
1716       TopoDS_Shape curface = tmpF.EmptyCopied();
1717       B.Add(curface,wire);
1718       curface.Orientation ( myFace.Orientation() );
1719       if( ShapeAnalysis::IsOuterBound(TopoDS::Face(curface)))
1720         wire.Reverse();
1721     }
1722     B.Add ( tmpF, wire );
1723   }
1724 
1725   tmpF.Orientation ( myFace.Orientation() );
1726 
1727   // A special kind of FixShifted is necessary for torus-like
1728   // surfaces to adjust wires by period ALONG the missing SEAM direction
1729   // tr9_r0501-ug.stp #187640
1730   if ( uclosed && vclosed ) {
1731     Standard_Real shiftw2 =
1732       ShapeAnalysis::AdjustByPeriod ( 0.5 * ( m2[coord][0] + m2[coord][1] ),
1733                                       0.5 * ( m1[coord][0] + m1[coord][1]  +
1734                                               isneg * ( period + ::Precision::PConfusion() ) ),
1735                                       period );
1736     m1[coord][0] = Min ( m1[coord][0], m2[coord][0] + shiftw2 );
1737     m1[coord][1] = Max ( m1[coord][1], m2[coord][1] + shiftw2 );
1738     for ( TopoDS_Iterator it(tmpF,Standard_False); it.More(); it.Next() ) {
1739       if(it.Value().ShapeType() != TopAbs_WIRE)
1740         continue;
1741       TopoDS_Wire w = TopoDS::Wire ( it.Value() );
1742       if ( w == w11 ) continue;
1743       Standard_Real shift;
1744       if ( w == w21 ) shift = shiftw2;
1745 
1746       else {
1747 	S = tmpF.EmptyCopied();
1748 	B.Add ( S, w );
1749 	ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m2[0][0], m2[0][1], m2[1][0], m2[1][1]);
1750 	shift = ShapeAnalysis::AdjustByPeriod ( 0.5 * ( m2[coord][0] + m2[coord][1] ),
1751                                                 0.5 * ( m1[coord][0] + m1[coord][1] ), period );
1752       }
1753       if ( shift != 0. ) {
1754 	gp_Vec2d V(0.,0.);
1755 	V.SetCoord ( coord+1, shift );
1756 	ShapeAnalysis_Edge sae;
1757 	for ( TopoDS_Iterator iw(w); iw.More(); iw.Next() ) {
1758 	  TopoDS_Edge E = TopoDS::Edge ( iw.Value() );
1759 	  Handle(Geom2d_Curve) C;
1760 	  Standard_Real a, b;
1761 	  if ( ! sae.PCurve ( E, tmpF, C, a, b ) ) continue;
1762 	  C->Translate ( V );
1763 	}
1764       }
1765     }
1766     // abv 05 Feb 02: OCC34
1767     // by the way, select proper split place by V to avoid extra intersections
1768     if ( m1[coord][1] - m1[coord][0] <= period ) {
1769       Standard_Real other = 0.5 * ( m1[coord][0] + m1[coord][1] - period );
1770       if ( ismodeu ) vf = other;
1771       else uf = other;
1772     }
1773   }
1774 
1775   // find the best place by u and v to insert a seam
1776   // (so as to minimize splitting edges as possible)
1777   ShapeAnalysis_Edge sae;
1778   Standard_Integer foundU=0, foundV=0;
1779   Standard_Integer nb1 = wd1->NbEdges();
1780   Standard_Integer nb2 = wd2->NbEdges();
1781   for ( Standard_Integer i1 = 1; i1 <= nb1 + nb2; i1++ ) {
1782     TopoDS_Edge edge1 = ( i1 <= nb1 ? wd1->Edge ( i1 ) : wd2->Edge ( i1-nb1 ) );
1783     Handle(Geom2d_Curve) c2d;
1784     Standard_Real f, l;
1785     if ( ! sae.PCurve ( edge1, tmpF, c2d, f, l, Standard_True ) ) return Standard_False;
1786     gp_Pnt2d pos1 = c2d->Value(l).XY();
1787     // the best place is end of edge which is nearest to 0
1788     Standard_Boolean skipU = ! uclosed;
1789     if ( uclosed && ismodeu ) {
1790       pos1.SetX ( pos1.X() + ShapeAnalysis::AdjustByPeriod ( pos1.X(), SUF, URange ) );
1791       if ( foundU ==2 && Abs ( pos1.X() ) > Abs(uf) ) skipU = Standard_True;
1792       else if ( ! foundU || ( foundU ==1 && Abs ( pos1.X() ) < Abs(uf) ) ) {
1793 	foundU = 1;
1794 	uf = pos1.X();
1795       }
1796     }
1797     Standard_Boolean skipV = ! vclosed;
1798     if ( vclosed && ! ismodeu ) {
1799       pos1.SetY ( pos1.Y() + ShapeAnalysis::AdjustByPeriod ( pos1.Y(), SVF, VRange ) );
1800       if ( foundV ==2 && Abs ( pos1.Y() ) > Abs(vf) ) skipV = Standard_True;
1801       else if ( ! foundV || ( foundV ==1 && Abs ( pos1.Y() ) < Abs(vf) ) ) {
1802 	foundV = 1;
1803 	vf = pos1.Y();
1804       }
1805     }
1806     if ( skipU && skipV ) {
1807       if ( i1 <= nb1 ) continue;
1808       else break;
1809     }
1810     // or yet better - if it is end of some edges on both wires
1811     for ( Standard_Integer i2 = 1; i1 <= nb1 && i2 <= nb2; i2++ ) {
1812       TopoDS_Edge edge2 = wd2->Edge ( i2 );
1813       if ( ! sae.PCurve ( edge2, tmpF, c2d, f, l, Standard_True ) ) return Standard_False;
1814       gp_Pnt2d pos2 = c2d->Value(f).XY();
1815       if ( uclosed && ismodeu ) {
1816 	pos2.SetX ( pos2.X() + ShapeAnalysis::AdjustByPeriod ( pos2.X(), pos1.X(), URange ) );
1817 	if ( Abs ( pos2.X() - pos1.X() ) < ::Precision::PConfusion() &&
1818              ( foundU != 2 || Abs ( pos1.X() ) < Abs ( uf ) ) ) {
1819 	  foundU = 2;
1820 	  uf = pos1.X();
1821 	}
1822       }
1823       if ( vclosed && ! ismodeu ) {
1824 	pos2.SetY ( pos2.Y() + ShapeAnalysis::AdjustByPeriod ( pos2.Y(), pos1.Y(), VRange ) );
1825 	if ( Abs ( pos2.Y() - pos1.Y() ) < ::Precision::PConfusion() &&
1826              ( foundV != 2 || Abs ( pos1.Y() ) < Abs ( vf ) ) ) {
1827 	  foundV = 2;
1828 	  vf = pos1.Y();
1829 	}
1830       }
1831     }
1832   }
1833 
1834   //pdn fixing RTS on offsets
1835   if ( uf < SUF || uf > SUL )
1836     uf+=ShapeAnalysis::AdjustToPeriod(uf,SUF,SUF+URange);
1837   if ( vf < SVF || vf > SVL )
1838     vf+=ShapeAnalysis::AdjustToPeriod(vf,SVF,SVF+VRange);
1839 
1840   // Create fictive grid and call ComposeShell to insert a seam
1841   Handle(Geom_RectangularTrimmedSurface) RTS =
1842     new Geom_RectangularTrimmedSurface ( mySurf->Surface(), uf, uf+URange, vf, vf+VRange );
1843   Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
1844   grid->SetValue ( 1, 1, RTS ); //mySurf->Surface() );
1845   Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
1846   TopLoc_Location L;
1847 
1848   //addition non-manifold topology
1849   Standard_Integer j=1;
1850   for( ; j <= aSeqNonManif.Length(); j++)
1851     B.Add(tmpF,aSeqNonManif.Value(j));
1852 
1853   ShapeFix_ComposeShell CompShell;
1854 //  TopoDS_Face tmpF = myFace;
1855 //  tmpF.Orientation(TopAbs_FORWARD);
1856   CompShell.Init ( G, L, tmpF, ::Precision::Confusion() );//myPrecision
1857   if ( Context().IsNull() ) SetContext ( new ShapeBuild_ReShape );
1858   CompShell.ClosedMode() = Standard_True;
1859   CompShell.SetContext( Context() );
1860   CompShell.SetMaxTolerance(MaxTolerance());
1861   CompShell.Perform();
1862 
1863   // abv 03.07.00: CAX-IF TRJ4: trj4_k1_goe-tu-214.stp: #785: reset mySurf
1864   mySurf = new ShapeAnalysis_Surface ( RTS );
1865 
1866   myResult = CompShell.Result();
1867 
1868   Context()->Replace ( myFace, myResult );
1869 
1870   // Remove small wires and / or faces that can be generated by ComposeShell
1871   // (see tests bugs step bug30052_4, de step_3 E6)
1872   Standard_Integer nbFaces = 0;
1873   TopExp_Explorer expF ( myResult, TopAbs_FACE );
1874   for (; expF.More(); expF.Next() )
1875   {
1876     TopoDS_Face aFace = TopoDS::Face(expF.Value());
1877     TopExp_Explorer aExpW(aFace, TopAbs_WIRE);
1878     Standard_Integer nbWires = 0;
1879     for( ;aExpW.More(); aExpW.Next() )
1880     {
1881       ShapeFix_Wire aSfw(TopoDS::Wire(aExpW.Value()), aFace, Precision());
1882       aSfw.SetContext(Context());
1883       if(aSfw.NbEdges())
1884         aSfw.FixSmall (Standard_True, Precision());
1885       if(!aSfw.NbEdges())
1886       {
1887         Context()->Remove(aExpW.Value());
1888         continue;
1889       }
1890       nbWires++;
1891     }
1892     if(!nbWires)
1893     {
1894       Context()->Remove(aFace);
1895       continue;
1896     }
1897     nbFaces++;
1898   }
1899 
1900   myResult = Context()->Apply(myResult);
1901   for (TopExp_Explorer exp ( myResult, TopAbs_FACE ); exp.More(); exp.Next() ) {
1902     myFace = TopoDS::Face ( Context()->Apply(exp.Current() ));
1903     if( myFace.IsNull())
1904       continue;
1905     if(nbFaces > 1)
1906     {
1907       FixSmallAreaWire(Standard_True);
1908       TopoDS_Shape aShape = Context()->Apply(myFace);
1909       if(aShape.IsNull() )
1910         continue;
1911       myFace = TopoDS::Face(aShape);
1912     }
1913     BRepTools::Update(myFace); //:p4
1914   }
1915   myResult = Context()->Apply(myResult);
1916 
1917   SendWarning ( Message_Msg ( "FixAdvFace.FixMissingSeam.MSG0" ) );// Missing seam-edge added
1918   return Standard_True;
1919 }
1920 
1921 //=======================================================================
1922 //function : FixSmallAreaWire
1923 //purpose  :
1924 //=======================================================================
1925 //%14 pdn 24.02.99 PRO10109, USA60293 fix wire on face with small area.
FixSmallAreaWire(const Standard_Boolean theIsRemoveSmallFace)1926 Standard_Boolean ShapeFix_Face::FixSmallAreaWire(const Standard_Boolean theIsRemoveSmallFace)
1927 {
1928   if ( !Context().IsNull() )
1929   {
1930     TopoDS_Shape aShape = Context()->Apply(myFace);
1931     myFace = TopoDS::Face(aShape);
1932   }
1933 
1934   BRep_Builder aBuilder;
1935   Standard_Integer nbRemoved = 0, nbWires = 0;
1936 
1937   TopoDS_Shape anEmptyCopy = myFace.EmptyCopied();
1938   TopoDS_Face  aFace = TopoDS::Face(anEmptyCopy);
1939   aFace.Orientation (TopAbs_FORWARD);
1940 
1941   const Standard_Real aTolerance3d = ShapeFix_Root::Precision();
1942   for (TopoDS_Iterator aWIt(myFace, Standard_False); aWIt.More(); aWIt.Next())
1943   {
1944     const TopoDS_Shape& aShape = aWIt.Value();
1945     if ( aShape.ShapeType()   != TopAbs_WIRE    &&
1946          aShape.Orientation() != TopAbs_FORWARD &&
1947          aShape.Orientation() != TopAbs_REVERSED )
1948     {
1949       continue;
1950     }
1951 
1952     const TopoDS_Wire&         aWire       = TopoDS::Wire(aShape);
1953     Handle(ShapeAnalysis_Wire) anAnalyzer  = new ShapeAnalysis_Wire(aWire, myFace, aTolerance3d);
1954     if ( anAnalyzer->CheckSmallArea(aWire) )
1955     {
1956       // Null area wire detected, wire skipped
1957       SendWarning(aWire, Message_Msg("FixAdvFace.FixSmallAreaWire.MSG0"));
1958       ++nbRemoved;
1959     }
1960     else
1961     {
1962       aBuilder.Add(aFace, aWire);
1963       ++nbWires;
1964     }
1965   }
1966 
1967   if ( nbRemoved <= 0 )
1968     return Standard_False;
1969 
1970   if ( nbWires <= 0 )
1971   {
1972 #ifdef OCCT_DEBUG
1973     std::cout << "Warning: ShapeFix_Face: All wires on a face have small area; left untouched" << std::endl;
1974 #endif
1975     if ( theIsRemoveSmallFace && !Context().IsNull() )
1976       Context()->Remove(myFace);
1977 
1978     return Standard_False;
1979   }
1980 #ifdef OCCT_DEBUG
1981   std::cout << "Warning: ShapeFix_Face: " << nbRemoved << " small area wire(s) removed" << std::endl;
1982 #endif
1983   aFace.Orientation (myFace.Orientation ());
1984   if (!Context ().IsNull ())
1985     Context ()->Replace (myFace, aFace);
1986 
1987   myFace = aFace;
1988   return Standard_True;
1989 }
1990 //=======================================================================
1991 //function : FixLoopWire
1992 //purpose  :
1993 //=======================================================================
FindNext(const TopoDS_Shape & aVert,const TopoDS_Shape & ainitEdge,TopTools_IndexedMapOfShape & aMapVertices,TopTools_DataMapOfShapeListOfShape & aMapVertexEdges,const TopTools_MapOfShape & aMapSmallEdges,const TopTools_MapOfShape & aMapSeemEdges,TopTools_MapOfShape & aMapEdges,Handle (ShapeExtend_WireData)& aWireData)1994 static void FindNext(const TopoDS_Shape& aVert,
1995                      const TopoDS_Shape& ainitEdge,
1996                      TopTools_IndexedMapOfShape& aMapVertices,
1997                      TopTools_DataMapOfShapeListOfShape& aMapVertexEdges,
1998                      const TopTools_MapOfShape& aMapSmallEdges,
1999                      const TopTools_MapOfShape& aMapSeemEdges,
2000                      TopTools_MapOfShape& aMapEdges,
2001                      Handle(ShapeExtend_WireData)& aWireData)
2002 {
2003   TopoDS_Iterator aItV(ainitEdge);
2004   TopoDS_Shape anextVert = aVert;
2005   Standard_Boolean isFind = Standard_False;
2006   for( ; aItV.More() && !isFind; aItV.Next())
2007   {
2008     if(!aItV.Value().IsSame(aVert) ) {
2009       isFind = Standard_True;
2010       anextVert = aItV.Value();
2011 
2012     }
2013   }
2014 
2015   if(!isFind && !aMapSmallEdges.Contains(ainitEdge))
2016     return;
2017   if(isFind && aMapVertices.Contains(anextVert))
2018     return;
2019 
2020   const TopTools_ListOfShape& aledges = aMapVertexEdges.Find(anextVert);
2021   TopTools_ListIteratorOfListOfShape liter(aledges);
2022   isFind = Standard_False;
2023   TopoDS_Shape anextEdge;
2024   for( ; liter.More() && !isFind; liter.Next())
2025   {
2026     if(!aMapEdges.Contains(liter.Value()) && !liter.Value().IsSame(ainitEdge)) {
2027       anextEdge = liter.Value();
2028       aWireData->Add(anextEdge);
2029       if(aMapSeemEdges.Contains(anextEdge))
2030         aWireData->Add(anextEdge.Reversed());
2031       isFind = Standard_True;
2032       aMapEdges.Add(anextEdge);
2033       FindNext(anextVert,anextEdge,aMapVertices,aMapVertexEdges,aMapSmallEdges,aMapSeemEdges,aMapEdges,aWireData);
2034     }
2035   }
2036   return;
2037 }
2038 
isClosed2D(const TopoDS_Face & aFace,const TopoDS_Wire & aWire)2039 static Standard_Boolean isClosed2D(const TopoDS_Face& aFace,const TopoDS_Wire& aWire)
2040 {
2041   Standard_Boolean isClosed = Standard_True;
2042   Handle(ShapeAnalysis_Wire) asaw = new ShapeAnalysis_Wire(aWire,aFace,Precision::Confusion());
2043   for (Standard_Integer i = 1; i <= asaw->NbEdges() && isClosed; i++) {
2044     TopoDS_Edge edge1 = asaw->WireData()->Edge(i);
2045     //checking that wire is closed in 2D space with tolerance of vertex.
2046     ShapeAnalysis_Edge sae;
2047     TopoDS_Vertex v1 = sae.FirstVertex(edge1);
2048     asaw->SetPrecision(BRep_Tool::Tolerance(v1));
2049     asaw->CheckGap2d(i);
2050     isClosed = (asaw->LastCheckStatus(ShapeExtend_OK));
2051 
2052   }
2053   return isClosed;
2054 }
2055 
2056 //=======================================================================
2057 //function : FixLoopWire
2058 //purpose  :
2059 //=======================================================================
2060 
FixLoopWire(TopTools_SequenceOfShape & aResWires)2061 Standard_Boolean ShapeFix_Face::FixLoopWire(TopTools_SequenceOfShape& aResWires)
2062 {
2063   TopTools_IndexedMapOfShape aMapVertices;
2064   TopTools_DataMapOfShapeListOfShape aMapVertexEdges;
2065   TopTools_MapOfShape aMapSmallEdges;
2066   TopTools_MapOfShape aMapSeemEdges;
2067   if(!FixWireTool()->Analyzer()->CheckLoop(aMapVertices, aMapVertexEdges,aMapSmallEdges,aMapSeemEdges))
2068     return Standard_False;
2069 
2070 
2071   TopTools_MapOfShape aMapEdges;
2072   TopTools_SequenceOfShape aSeqWires;
2073 
2074   //collecting wires from common vertex belonging more than 2 edges
2075   Standard_Integer i =1;
2076   for( ; i <= aMapVertices.Extent(); i++) {
2077     TopoDS_Shape aVert = aMapVertices.FindKey(i);
2078     const TopTools_ListOfShape& aledges = aMapVertexEdges.Find(aVert);
2079     TopTools_ListIteratorOfListOfShape liter(aledges);
2080     for( ; liter.More(); liter.Next())
2081     {
2082       TopoDS_Edge Edge = TopoDS::Edge(liter.Value());
2083       if(aMapEdges.Contains(Edge))
2084         continue;
2085 
2086       Handle(ShapeExtend_WireData) aWireData = new ShapeExtend_WireData;
2087       aWireData->Add(Edge);
2088        if(aMapSeemEdges.Contains(Edge))
2089         aWireData->Add(Edge.Reversed());
2090       aMapEdges.Add(Edge);
2091       FindNext(aVert,Edge,aMapVertices,aMapVertexEdges,aMapSmallEdges,aMapSeemEdges,aMapEdges,aWireData);
2092       if(aWireData->NbEdges() ==1 && aMapSmallEdges.Contains(aWireData->Edge(1)))
2093         continue;
2094       TopoDS_Vertex aV1,aV2;
2095       TopoDS_Wire aWire = aWireData->Wire();
2096       TopExp::Vertices(aWire,aV1,aV2);
2097 
2098       if(aV1.IsSame(aV2)) {
2099         Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
2100         Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
2101         asfw->Load(asewd);
2102         asfw->FixReorder();
2103         TopoDS_Wire awire2 = asfw->Wire();
2104         aResWires.Append(awire2);
2105 
2106       }
2107       else aSeqWires.Append(aWireData->Wire());
2108     }
2109   }
2110 
2111 
2112   if(aSeqWires.Length() ==1) {
2113     aResWires.Append(aSeqWires.Value(1));
2114   }
2115   else {
2116     //collecting whole wire from two not closed wires having two common vertices.
2117     for( i =1; i <= aSeqWires.Length(); i++) {
2118       TopoDS_Vertex aV1,aV2;
2119       TopoDS_Wire aWire = TopoDS::Wire(aSeqWires.Value(i));
2120       TopExp::Vertices(aWire,aV1,aV2);
2121       Standard_Integer j = i+1;
2122       for( ; j <= aSeqWires.Length(); j++)
2123       {
2124         TopoDS_Vertex aV21,aV22;
2125         TopoDS_Wire aWire2 = TopoDS::Wire(aSeqWires.Value(j));
2126         TopExp::Vertices(aWire2,aV21,aV22);
2127         if((aV1.IsSame(aV21) || aV1.IsSame(aV22)) && (aV2.IsSame(aV21) || aV2.IsSame(aV22)))
2128         {
2129           Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
2130           asewd->Add(aWire2);
2131           Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
2132           asfw->Load(asewd);
2133           asfw->FixReorder();
2134           aResWires.Append(asfw->Wire());
2135           aSeqWires.Remove(j--);
2136           myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
2137           break;
2138         }
2139 
2140       }
2141       if(j <= aSeqWires.Length())
2142         aSeqWires.Remove(i--);
2143 
2144     }
2145     if(aSeqWires.Length()<3) {
2146       for( i =1; i <= aSeqWires.Length(); i++)
2147         aResWires.Append(aSeqWires.Value(i));
2148 
2149     }
2150     else {
2151       //collecting wires having one common vertex
2152       for( i =1; i <= aSeqWires.Length(); i++) {
2153         TopoDS_Vertex aV1,aV2;
2154         TopoDS_Wire aWire = TopoDS::Wire(aSeqWires.Value(i));
2155         TopExp::Vertices(aWire,aV1,aV2);
2156         Standard_Integer j =i+1;
2157         for( ; j <= aSeqWires.Length(); j++)
2158         {
2159           TopoDS_Vertex aV21,aV22;
2160           TopoDS_Wire aWire2 = TopoDS::Wire(aSeqWires.Value(j));
2161           TopExp::Vertices(aWire2,aV21,aV22);
2162           if((aV1.IsSame(aV21) || aV1.IsSame(aV22)) || (aV2.IsSame(aV21) || aV2.IsSame(aV22)))
2163           {
2164             Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
2165             asewd->Add(aWire2);
2166             Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
2167             asfw->Load(asewd);
2168             asfw->FixReorder();
2169             aWire =  asfw->Wire();
2170             TopExp::Vertices(aWire,aV1,aV2);
2171             aSeqWires.Remove(j--);
2172             myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
2173           }
2174         }
2175         aResWires.Append(aWire);
2176 
2177       }
2178     }
2179   }
2180   Standard_Boolean isClosed = Standard_True;
2181 
2182   //checking that obtained wires is closed in 2D space
2183   if (mySurf->Adaptor3d()->GetType() != GeomAbs_Plane) {
2184 
2185     TopoDS_Shape emptyCopied = myFace.EmptyCopied();
2186     TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
2187     tmpFace.Orientation ( TopAbs_FORWARD );
2188 
2189     for(i =1; i <= aResWires.Length() && isClosed; i++) {
2190       TopoDS_Wire awire = TopoDS::Wire(aResWires.Value(i));
2191       isClosed = isClosed2D(tmpFace,awire);
2192     }
2193   }
2194 
2195   Standard_Boolean isDone =(aResWires.Length() && isClosed);
2196   if(isDone && aResWires.Length() >1)
2197   {
2198 #ifdef OCCT_DEBUG
2199     std::cout<<"Wire was split on "<<aResWires.Length()<<" wires"<< std::endl;
2200 #endif
2201   }
2202 
2203   return isDone;
2204 }
2205 
2206 //=======================================================================
2207 //function : SplitEdge
2208 //purpose  :
2209 //=======================================================================
2210 
SplitEdge(const Handle (ShapeExtend_WireData)& sewd,const Standard_Integer num,const Standard_Real param,const TopoDS_Vertex & vert,const Standard_Real preci,ShapeFix_DataMapOfShapeBox2d & boxes)2211 Standard_Boolean ShapeFix_Face::SplitEdge(const Handle(ShapeExtend_WireData)& sewd,
2212                                           const Standard_Integer num,
2213                                           const Standard_Real param,
2214                                           const TopoDS_Vertex& vert,
2215                                           const Standard_Real preci,
2216                                           ShapeFix_DataMapOfShapeBox2d& boxes)
2217 {
2218   TopoDS_Edge edge = sewd->Edge(num);
2219   TopoDS_Edge newE1, newE2;
2220   ShapeFix_SplitTool aTool;
2221   if(aTool.SplitEdge(edge,param,vert,myFace,newE1,newE2,preci,0.01*preci)) {
2222     // change context
2223     Handle(ShapeExtend_WireData) wd = new ShapeExtend_WireData;
2224     wd->Add(newE1);
2225     wd->Add(newE2);
2226     if(!Context().IsNull()) Context()->Replace( edge, wd->Wire() );
2227     for (TopExp_Explorer exp ( wd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) {
2228       TopoDS_Edge E = TopoDS::Edge ( exp.Current() );
2229       BRepTools::Update(E);
2230     }
2231 
2232 //    for ( Standard_Integer i=1; i <= sewd->NbEdges(); i++ ) {
2233 //      TopoDS_Edge E = sewd->Edge(i);
2234 //      TopoDS_Shape S = Context()->Apply ( E );
2235 //      if ( S == E ) continue;
2236 //      for ( TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next() )
2237 //        sewd->Add ( exp.Current(), i++ );
2238 //      sewd->Remove ( i-- );
2239 //    }
2240 
2241     // change sewd and boxes
2242     sewd->Set(newE1,num);
2243     if(num==sewd->NbEdges())
2244       sewd->Add(newE2);
2245     else
2246       sewd->Add(newE2,num+1);
2247 
2248     boxes.UnBind(edge);
2249     TopLoc_Location L;
2250     const Handle(Geom_Surface)& S = BRep_Tool::Surface(myFace,L);
2251     Handle(Geom2d_Curve) c2d;
2252     Standard_Real cf,cl;
2253     ShapeAnalysis_Edge sae;
2254     if(sae.PCurve(newE1,S,L,c2d,cf,cl,Standard_False)) {
2255       Bnd_Box2d box;
2256       Geom2dAdaptor_Curve gac;
2257       Standard_Real aFirst = c2d->FirstParameter();
2258       Standard_Real aLast = c2d->LastParameter();
2259       if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2260          && (cf < aFirst || cl > aLast)) {
2261         //pdn avoiding problems with segment in Bnd_Box
2262         gac.Load(c2d);
2263       }
2264       else
2265         gac.Load(c2d,cf,cl);
2266       BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2267       boxes.Bind(newE1,box);
2268     }
2269     if(sae.PCurve(newE2,S,L,c2d,cf,cl,Standard_False)) {
2270       Bnd_Box2d box;
2271       Geom2dAdaptor_Curve gac;
2272       Standard_Real aFirst = c2d->FirstParameter();
2273       Standard_Real aLast = c2d->LastParameter();
2274       if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2275          && (cf < aFirst || cl > aLast)) {
2276         //pdn avoiding problems with segment in Bnd_Box
2277         gac.Load(c2d);
2278       }
2279       else
2280         gac.Load(c2d,cf,cl);
2281       BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2282       boxes.Bind(newE2,box);
2283     }
2284     return Standard_True;
2285   }
2286   return Standard_False;
2287 }
2288 
2289 
2290 //=======================================================================
2291 //function : SplitEdge
2292 //purpose  :
2293 //=======================================================================
2294 
SplitEdge(const Handle (ShapeExtend_WireData)& sewd,const Standard_Integer num,const Standard_Real param1,const Standard_Real param2,const TopoDS_Vertex & vert,const Standard_Real preci,ShapeFix_DataMapOfShapeBox2d & boxes)2295 Standard_Boolean ShapeFix_Face::SplitEdge(const Handle(ShapeExtend_WireData)& sewd,
2296                                           const Standard_Integer num,
2297                                           const Standard_Real param1,
2298                                           const Standard_Real param2,
2299                                           const TopoDS_Vertex& vert,
2300                                           const Standard_Real preci,
2301                                           ShapeFix_DataMapOfShapeBox2d& boxes)
2302 {
2303   TopoDS_Edge edge = sewd->Edge(num);
2304   TopoDS_Edge newE1, newE2;
2305   ShapeFix_SplitTool aTool;
2306   if(aTool.SplitEdge(edge,param1,param2,vert,myFace,newE1,newE2,preci,0.01*preci)) {
2307     // change context
2308     Handle(ShapeExtend_WireData) wd = new ShapeExtend_WireData;
2309     wd->Add(newE1);
2310     wd->Add(newE2);
2311     if(!Context().IsNull()) Context()->Replace( edge, wd->Wire() );
2312     for (TopExp_Explorer exp ( wd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) {
2313       TopoDS_Edge E = TopoDS::Edge ( exp.Current() );
2314       BRepTools::Update(E);
2315     }
2316 
2317     // change sewd and boxes
2318     sewd->Set(newE1,num);
2319     if(num==sewd->NbEdges())
2320       sewd->Add(newE2);
2321     else
2322       sewd->Add(newE2,num+1);
2323 
2324     boxes.UnBind(edge);
2325     TopLoc_Location L;
2326     const Handle(Geom_Surface)& S = BRep_Tool::Surface(myFace,L);
2327     Handle(Geom2d_Curve) c2d;
2328     Standard_Real cf,cl;
2329     ShapeAnalysis_Edge sae;
2330     if(sae.PCurve(newE1,S,L,c2d,cf,cl,Standard_False)) {
2331       Bnd_Box2d box;
2332       Geom2dAdaptor_Curve gac;
2333       Standard_Real aFirst = c2d->FirstParameter();
2334       Standard_Real aLast = c2d->LastParameter();
2335       if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2336          && (cf < aFirst || cl > aLast)) {
2337         //pdn avoiding problems with segment in Bnd_Box
2338         gac.Load(c2d);
2339       }
2340       else
2341         gac.Load(c2d,cf,cl);
2342       BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2343       boxes.Bind(newE1,box);
2344     }
2345     if(sae.PCurve(newE2,S,L,c2d,cf,cl,Standard_False)) {
2346       Bnd_Box2d box;
2347       Geom2dAdaptor_Curve gac;
2348       Standard_Real aFirst = c2d->FirstParameter();
2349       Standard_Real aLast = c2d->LastParameter();
2350       if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2351          && (cf < aFirst || cl > aLast)) {
2352         //pdn avoiding problems with segment in Bnd_Box
2353         gac.Load(c2d);
2354       }
2355       else
2356         gac.Load(c2d,cf,cl);
2357       BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2358       boxes.Bind(newE2,box);
2359     }
2360     return Standard_True;
2361   }
2362   return Standard_False;
2363 }
2364 
2365 
2366 //=======================================================================
2367 //function : FixIntersectingWires
2368 //purpose  :
2369 //=======================================================================
2370 
FixIntersectingWires()2371 Standard_Boolean ShapeFix_Face::FixIntersectingWires()
2372 {
2373   ShapeFix_IntersectionTool ITool(Context(),Precision(),MaxTolerance());
2374   return ITool.FixIntersectingWires(myFace);
2375 }
2376 
2377 
2378 //=======================================================================
2379 //function : FixWiresTwoCoincEdges
2380 //purpose  :
2381 //=======================================================================
2382 
FixWiresTwoCoincEdges()2383 Standard_Boolean ShapeFix_Face::FixWiresTwoCoincEdges()
2384 {
2385   if ( ! Context().IsNull() ) {
2386     TopoDS_Shape S = Context()->Apply ( myFace );
2387     myFace = TopoDS::Face ( S );
2388   }
2389 
2390   TopAbs_Orientation ori = myFace.Orientation();
2391   TopoDS_Shape emptyCopied = myFace.EmptyCopied();
2392   TopoDS_Face face = TopoDS::Face (emptyCopied);
2393   face.Orientation(TopAbs_FORWARD);
2394   Standard_Integer nbWires = 0;
2395   BRep_Builder B;
2396 
2397   for (TopoDS_Iterator it (myFace, Standard_False); it.More(); it.Next()) {
2398     if(it.Value().ShapeType() != TopAbs_WIRE ||
2399        (it.Value().Orientation() != TopAbs_FORWARD && it.Value().Orientation() != TopAbs_REVERSED)) {
2400         continue;
2401     }
2402     nbWires++;
2403   }
2404   if(nbWires<2) return Standard_False;
2405   Standard_Boolean isFixed = Standard_False;
2406   for (TopoDS_Iterator wi (myFace, Standard_False); wi.More(); wi.Next()) {
2407     if(wi.Value().ShapeType() != TopAbs_WIRE ||
2408        (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) {
2409       B.Add(face,wi.Value());
2410       continue;
2411     }
2412     TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
2413     Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
2414     if(sewd->NbEdges()==2) {
2415       TopoDS_Edge E1 = sewd->Edge(1);
2416       TopoDS_Edge E2 = sewd->Edge(2);
2417       E1.Orientation(TopAbs_FORWARD);
2418       E2.Orientation(TopAbs_FORWARD);
2419       if( !(E1==E2) ) {
2420         B.Add(face,wire);
2421       }
2422       else isFixed = Standard_True;
2423     }
2424     else {
2425       B.Add(face,wire);
2426     }
2427   }
2428   if(isFixed) {
2429     face.Orientation(ori);
2430     if ( ! Context().IsNull() ) Context()->Replace ( myFace, face );
2431     myFace = face;
2432   }
2433 
2434   return isFixed;
2435 }
2436 
2437 
2438 //=======================================================================
2439 //function : FixSplitFace
2440 //purpose  :
2441 //=======================================================================
2442 
FixSplitFace(const TopTools_DataMapOfShapeListOfShape & MapWires)2443 Standard_Boolean ShapeFix_Face::FixSplitFace(const TopTools_DataMapOfShapeListOfShape &MapWires)
2444 {
2445   BRep_Builder B;
2446   TopTools_SequenceOfShape faces;
2447   TopoDS_Shape S = myFace;
2448   if ( ! Context().IsNull() )
2449     S = Context()->Apply ( myFace );
2450   Standard_Integer NbWires=0, NbWiresNew=0, NbEdges;
2451   for(TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
2452     const TopoDS_Shape& aShape = iter.Value();
2453     if(aShape.ShapeType() != TopAbs_WIRE ||
2454        (aShape.Orientation() != TopAbs_FORWARD && aShape.Orientation() != TopAbs_REVERSED))
2455         continue;
2456     TopoDS_Wire wire = TopoDS::Wire ( aShape );
2457     NbWires++;
2458     if(MapWires.IsBound(wire)) {
2459       // if wire not closed --> stop split and return false
2460       Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
2461       NbEdges = sewd->NbEdges();
2462       if (NbEdges == 0) {
2463         continue;
2464       }
2465       //
2466       TopoDS_Edge E1 = sewd->Edge(1);
2467       TopoDS_Edge E2 = sewd->Edge(NbEdges);
2468       TopoDS_Vertex V1,V2;
2469       ShapeAnalysis_Edge sae;
2470       V1=sae.FirstVertex(E1);
2471       V2=sae.LastVertex(E2);
2472       if(!V1.IsSame(V2)) {
2473 #ifdef OCCT_DEBUG
2474         std::cout<<"wire not closed --> stop split"<<std::endl;
2475 #endif
2476         return Standard_False;
2477       }
2478       // create face
2479       TopoDS_Shape emptyCopied = S.EmptyCopied();
2480       TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
2481       tmpFace.Orientation ( TopAbs_FORWARD );
2482       B.Add(tmpFace,wire);
2483       NbWiresNew++;
2484       const TopTools_ListOfShape& IntWires = MapWires.Find(wire);
2485       TopTools_ListIteratorOfListOfShape liter(IntWires);
2486       for( ; liter.More(); liter.Next()) {
2487         TopoDS_Shape aShapeEmptyCopied = tmpFace.EmptyCopied();
2488         TopoDS_Face aFace = TopoDS::Face ( aShapeEmptyCopied);
2489         aFace.Orientation ( TopAbs_FORWARD );
2490         B.Add (aFace,liter.Value());
2491         BRepTopAdaptor_FClass2d clas (aFace,::Precision::PConfusion());
2492         TopAbs_State staout = clas.PerformInfinitePoint();
2493         if (staout == TopAbs_IN)
2494           B.Add(tmpFace,liter.Value());
2495         else
2496           B.Add(tmpFace,liter.Value().Reversed());
2497         NbWiresNew++;
2498       }
2499       if(!myFwd) tmpFace.Orientation(TopAbs_REVERSED);
2500       faces.Append(tmpFace);
2501     }
2502   }
2503 
2504   if(NbWires!=NbWiresNew) return Standard_False;
2505 
2506   if(faces.Length()>1) {
2507     TopoDS_Compound Comp;
2508     B.MakeCompound(Comp);
2509     for(Standard_Integer i=1; i<=faces.Length(); i++ )
2510       B.Add(Comp,faces(i));
2511     myResult = Comp;
2512 
2513     if(!Context().IsNull())
2514     {
2515       Context()->Replace ( myFace, myResult );
2516     }
2517 
2518     for (TopExp_Explorer exp ( myResult, TopAbs_FACE ); exp.More(); exp.Next() ) {
2519       myFace = TopoDS::Face ( exp.Current() );
2520       BRepTools::Update(myFace);
2521     }
2522     return Standard_True;
2523   }
2524 
2525   return Standard_False;
2526 }
2527 
2528 //=======================================================================
2529 //function : IsPeriodicConicalLoop
2530 //purpose  : Checks whether the passed wire makes up a periodic loop on
2531 //           passed conical surface
2532 //=======================================================================
2533 
IsPeriodicConicalLoop(const Handle (Geom_ConicalSurface)& theSurf,const TopoDS_Wire & theWire,const Standard_Real theTolerance,Standard_Real & theMinU,Standard_Real & theMaxU,Standard_Real & theMinV,Standard_Real & theMaxV,Standard_Boolean & isUDecrease)2534 static Standard_Boolean IsPeriodicConicalLoop(const Handle(Geom_ConicalSurface)& theSurf,
2535                                               const TopoDS_Wire& theWire,
2536                                               const Standard_Real theTolerance,
2537                                               Standard_Real& theMinU,
2538                                               Standard_Real& theMaxU,
2539                                               Standard_Real& theMinV,
2540                                               Standard_Real& theMaxV,
2541                                               Standard_Boolean& isUDecrease)
2542 {
2543   if ( theSurf.IsNull() )
2544     return Standard_False;
2545 
2546   ShapeAnalysis_Edge aSAE;
2547   TopLoc_Location aLoc;
2548 
2549   Standard_Real aCumulDeltaU = 0.0, aCumulDeltaUAbs = 0.0;
2550   Standard_Real aMinU = RealLast();
2551   Standard_Real aMinV = aMinU;
2552   Standard_Real aMaxU = -aMinU;
2553   Standard_Real aMaxV = aMaxU;
2554 
2555   // Iterate over the edges to check whether the wire is periodic on conical surface
2556   TopoDS_Iterator aWireIter(theWire, Standard_False);
2557   for ( ; aWireIter.More(); aWireIter.Next() )
2558   {
2559     const TopoDS_Edge& aCurrentEdge = TopoDS::Edge(aWireIter.Value());
2560     Handle(Geom2d_Curve) aC2d;
2561     Standard_Real aPFirst, aPLast;
2562 
2563     aSAE.PCurve(aCurrentEdge, theSurf, aLoc, aC2d, aPFirst, aPLast, Standard_True);
2564 
2565     if ( aC2d.IsNull() )
2566       return Standard_False;
2567 
2568     gp_Pnt2d aUVFirst = aC2d->Value(aPFirst),
2569              aUVLast = aC2d->Value(aPLast);
2570 
2571     Standard_Real aUFirst = aUVFirst.X(), aULast = aUVLast.X();
2572     Standard_Real aVFirst = aUVFirst.Y(), aVLast = aUVLast.Y();
2573 
2574     Standard_Real aCurMaxU = Max(aUFirst, aULast),
2575                   aCurMinU = Min(aUFirst, aULast);
2576     Standard_Real aCurMaxV = Max(aVFirst, aVLast),
2577                   aCurMinV = Min(aVFirst, aVLast);
2578 
2579     if ( aCurMinU < aMinU )
2580       aMinU = aCurMinU;
2581     if ( aCurMaxU > aMaxU )
2582       aMaxU = aCurMaxU;
2583     if ( aCurMinV < aMinV )
2584       aMinV = aCurMinV;
2585     if ( aCurMaxV > aMaxV )
2586       aMaxV = aCurMaxV;
2587 
2588     Standard_Real aDeltaU = aULast - aUFirst;
2589 
2590     aCumulDeltaU += aDeltaU;
2591     aCumulDeltaUAbs += Abs(aDeltaU);
2592   }
2593 
2594   theMinU = aMinU;
2595   theMaxU = aMaxU;
2596   theMinV = aMinV;
2597   theMaxV = aMaxV;
2598   isUDecrease = (aCumulDeltaU < 0 ? Standard_True : Standard_False);
2599 
2600   Standard_Boolean is2PIDelta = Abs(aCumulDeltaUAbs - 2*M_PI) <= theTolerance;
2601   Standard_Boolean isAroundApex = Abs(theMaxU - theMinU) > 2*M_PI - theTolerance;
2602 
2603   return is2PIDelta && isAroundApex;
2604 }
2605 
2606 //=======================================================================
2607 //function : FixPeriodicDegenerated
2608 //purpose  :
2609 //=======================================================================
2610 
FixPeriodicDegenerated()2611 Standard_Boolean ShapeFix_Face::FixPeriodicDegenerated()
2612 {
2613   /* =====================
2614    *  Prepare fix routine
2615    * ===================== */
2616 
2617   if ( !Context().IsNull() )
2618   {
2619     TopoDS_Shape aSh = Context()->Apply(myFace);
2620     myFace = TopoDS::Face(aSh);
2621   }
2622 
2623   /* ================================================
2624    *  Check if fix can be applied on the passed face
2625    * ================================================ */
2626 
2627   // Collect all wires owned by the face
2628   TopTools_SequenceOfShape aWireSeq;
2629   for ( TopoDS_Iterator aWireIt(myFace, Standard_False); aWireIt.More(); aWireIt.Next() )
2630   {
2631     const TopoDS_Shape& aSubSh = aWireIt.Value();
2632     if (  aSubSh.ShapeType() != TopAbs_WIRE || ( aSubSh.Orientation() != TopAbs_FORWARD &&
2633                                                  aSubSh.Orientation() != TopAbs_REVERSED ) )
2634       continue;
2635 
2636     aWireSeq.Append( aWireIt.Value() );
2637   }
2638 
2639   // Get number of wires and surface
2640   Standard_Integer aNbWires = aWireSeq.Length();
2641   Handle(Geom_Surface) aSurface = BRep_Tool::Surface(myFace);
2642 
2643   // Only single wires on conical surfaces are checked
2644   if ( aNbWires != 1 || aSurface.IsNull() ||
2645        aSurface->DynamicType() != STANDARD_TYPE(Geom_ConicalSurface) )
2646     return Standard_False;
2647 
2648   // Get the single wire
2649   TopoDS_Wire aSoleWire = TopoDS::Wire( aWireSeq.Value(1) );
2650 
2651   // Check whether this wire is belting the conical surface by period
2652   Handle(Geom_ConicalSurface) aConeSurf = Handle(Geom_ConicalSurface)::DownCast(aSurface);
2653   Standard_Real aMinLoopU = 0.0, aMaxLoopU = 0.0, aMinLoopV = 0.0, aMaxLoopV = 0.0;
2654   Standard_Boolean isUDecrease = Standard_False;
2655 
2656   Standard_Boolean isConicLoop = IsPeriodicConicalLoop(aConeSurf, aSoleWire, Precision(),
2657                                                        aMinLoopU, aMaxLoopU,
2658                                                        aMinLoopV, aMaxLoopV,
2659                                                        isUDecrease);
2660 
2661   if ( !isConicLoop )
2662     return Standard_False;
2663 
2664   /* ===============
2665    *  Retrieve apex
2666    * =============== */
2667 
2668   // Get base circle of the conical surface (the circle it was built from)
2669   Handle(Geom_Curve) aConeBaseCrv = aConeSurf->VIso(0.0);
2670   Handle(Geom_Circle) aConeBaseCirc = Handle(Geom_Circle)::DownCast(aConeBaseCrv);
2671 
2672   // Retrieve conical props
2673   Standard_Real aConeBaseR = aConeBaseCirc->Radius();
2674   Standard_Real aSemiAngle = aConeSurf->SemiAngle();
2675 
2676   if ( fabs(aSemiAngle) <= Precision::Confusion() )
2677     return Standard_False; // Bad surface
2678 
2679   // Find the V parameter of the apex
2680   Standard_Real aConeBaseH = aConeBaseR / Sin(aSemiAngle);
2681   Standard_Real anApexV = -aConeBaseH;
2682 
2683   // Get apex vertex
2684   TopoDS_Vertex anApex = BRepBuilderAPI_MakeVertex( aConeSurf->Apex() );
2685 
2686   // ====================================
2687   //  Build degenerated edge in the apex
2688   // ====================================
2689 
2690   TopoDS_Edge anApexEdge;
2691   BRep_Builder aBuilder;
2692   aBuilder.MakeEdge(anApexEdge);
2693 
2694   // Check if positional relationship between the initial wire and apex
2695   // line in 2D is going to be consistent
2696   if ( fabs(anApexV - aMinLoopV) <= Precision() ||
2697        fabs(anApexV - aMaxLoopV) <= Precision() ||
2698       ( anApexV < aMaxLoopV && anApexV > aMinLoopV ) )
2699     return Standard_False;
2700 
2701   Handle(Geom2d_Line) anApexCurve2d;
2702 
2703   // Apex curve below the wire
2704   if ( anApexV < aMinLoopV )
2705   {
2706     anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMinLoopU, anApexV), gp_Dir2d(1, 0) );
2707     if ( !isUDecrease )
2708       aSoleWire.Reverse();
2709   }
2710 
2711   // Apex curve above the wire
2712   if ( anApexV > aMaxLoopV )
2713   {
2714     anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMaxLoopU, anApexV), gp_Dir2d(-1, 0) );
2715     if ( isUDecrease )
2716       aSoleWire.Reverse();
2717   }
2718 
2719   // Create degenerated edge & wire for apex
2720   aBuilder.UpdateEdge( anApexEdge, anApexCurve2d, myFace, Precision() );
2721   aBuilder.Add( anApexEdge, anApex );
2722   aBuilder.Add( anApexEdge, anApex.Reversed() );
2723   aBuilder.Degenerated(anApexEdge, Standard_True);
2724   aBuilder.Range( anApexEdge, 0, fabs(aMaxLoopU - aMinLoopU) );
2725   TopoDS_Wire anApexWire = BRepBuilderAPI_MakeWire(anApexEdge);
2726 
2727   // ===============================================================
2728   //  Finalize the fix building new face and setting up the results
2729   // ===============================================================
2730 
2731   // Collect the resulting set of wires
2732   TopTools_SequenceOfShape aNewWireSeq;
2733   aNewWireSeq.Append(aSoleWire);
2734   aNewWireSeq.Append(anApexWire);
2735 
2736   // Assemble new face
2737   TopoDS_Face aNewFace = TopoDS::Face( myFace.EmptyCopied() );
2738   aNewFace.Orientation(TopAbs_FORWARD);
2739   BRep_Builder aFaceBuilder;
2740   for ( Standard_Integer i = 1; i <= aNewWireSeq.Length(); i++ )
2741   {
2742     TopoDS_Wire aNewWire = TopoDS::Wire( aNewWireSeq.Value(i) );
2743     aFaceBuilder.Add(aNewFace, aNewWire);
2744   }
2745   aNewFace.Orientation( myFace.Orientation() );
2746 
2747   // Adjust the resulting state of the healing tool
2748   myResult = aNewFace;
2749   Context()->Replace(myFace, myResult);
2750 
2751   return Standard_True;
2752 }
2753