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