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