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