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