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