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