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