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