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