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