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