34e732bace25f8d145926cede91aa54f027eb846
[occt.git] / src / ShapeFix / ShapeFix_Wire.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 //:j6 abv 7 Dec 98: ProSTEP TR10 r0601_id.stp #57676 & #58586: 
15 //    in FixIntersectingEdges, do not cut edges because of influence on adjacent faces
16 // pdn 17.12.98: shifting whole wire in FixShifted
17 //:k3 abv 24 Dec 98: BUC50070 #26682 and #30087: removing self-int loops on pcurves
18 // pdn 30.12.98: PRO10366 #210: shifting pcurve between two singularities
19 // pdn 05.01.98: renaming method FixLittle to FixSmall
20 //:l0 abv 10.01.99: remove unused code
21 //:n2 abv 22.01.99: ma-test5.igs: IGES read (pref3d): remove degen edge with no pcurve
22 //:o4 abv 17.02.99: r0301_db.stp #53082: using parameter isClosed in CheckOrder
23 //:p4 abv 23.02.99: PRO9234 #15720: update UV points of edges after shifting pcurves
24 //#67 rln 01.03.99 S4135: ims010.igs treatment of Geom_SphericalSurface together with V-closed surfaces
25 //:p7 abv 10.03.99 PRO18206: using method IsDegenerated() to detect singularity in FixLacking
26 //:r0 abv 19.03.99 PRO7226.stp #489490: remove degenerated edges if several
27 //#78 rln 12.03.99 S4135: checking spatial closure with Precision
28 //#79 rln 15.03.99 S4135: bmarkmdl.igs: check for gap before shifting on singularities
29 //    pdn 17.03.99 S4135: implemented fixing not adjacent intersection
30 //#86 rln 22.03.99 S4135: repeat of fix self-intersection if it was fixed just before
31 //%15 pdn 06.04.99 CTS18546-2: fix of self-intersection is repeated while fixed
32 //#3  smh 01.04.99 S4163: Overflow   
33 //#4  szv          S4163: optimization
34 //:r7 abv 12.04.99 S4136: FixLk: extend cases of adding degenerated edge
35 //:r8 abv 12.04.99 PRO10107.stp #2241: try increasing tolerance of edge for fix IE
36 //:s2 abv 21.04.99 S4136, PRO7978.igs: FixLacking extended to be able to bend pcurves
37 //szv#9:S4244:19Aug99 Methods FixGaps3d and FixGaps2d were introduced
38 //#15 smh 03.04.2000 PRO19800. Checking degenerated point on a surface of revolution.
39 // sln 25.09.2001  checking order of 3d and 2d representation curves  
40 // van 19.10.2001  fix of non-adjacent self-intersection corrected to agree with BRepCheck
41 // skl 07.03.2002 fix for bug OCC180
42 // skl 15.05.2002 for OCC208 (if few edges have reference to 
43 //                one pcurve we make replace pcurve)
44 // PTV 26.06.2002  Remove regressions after fix OCC450
45
46 #include <Adaptor3d_CurveOnSurface.hxx>
47 #include <Bnd_Array1OfBox2d.hxx>
48 #include <Bnd_Box2d.hxx>
49 #include <BndLib_Add2dCurve.hxx>
50 #include <BRep_Builder.hxx>
51 #include <BRep_GCurve.hxx>
52 #include <BRep_ListIteratorOfListOfCurveRepresentation.hxx>
53 #include <BRep_TEdge.hxx>
54 #include <BRep_Tool.hxx>
55 #include <BRepBuilderAPI_MakeEdge.hxx>
56 #include <BRepBuilderAPI_MakeVertex.hxx>
57 #include <BRepTools.hxx>
58 #include <Geom2d_BSplineCurve.hxx>
59 #include <Geom2d_Curve.hxx>
60 #include <Geom2d_Line.hxx>
61 #include <Geom2d_TrimmedCurve.hxx>
62 #include <Geom2dAdaptor_Curve.hxx>
63 #include <Geom2dAdaptor_HCurve.hxx>
64 #include <Geom2dConvert.hxx>
65 #include <Geom_BSplineCurve.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_OffsetCurve.hxx>
68 #include <Geom_Plane.hxx>
69 #include <Geom_SphericalSurface.hxx>
70 #include <Geom_Surface.hxx>
71 #include <Geom_SurfaceOfRevolution.hxx>
72 #include <Geom_TrimmedCurve.hxx>
73 #include <GeomAdaptor_Curve.hxx>
74 #include <GeomAdaptor_HSurface.hxx>
75 #include <GeomAdaptor_Surface.hxx>
76 #include <GeomAPI.hxx>
77 #include <GeomAPI_ProjectPointOnCurve.hxx>
78 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
79 #include <gp_Pln.hxx>
80 #include <IntRes2d_IntersectionPoint.hxx>
81 #include <IntRes2d_SequenceOfIntersectionPoint.hxx>
82 #include <Message_Msg.hxx>
83 #include <Precision.hxx>
84 #include <ShapeAnalysis.hxx>
85 #include <ShapeAnalysis_Curve.hxx>
86 #include <ShapeAnalysis_Edge.hxx>
87 #include <ShapeAnalysis_Surface.hxx>
88 #include <ShapeAnalysis_TransferParameters.hxx>
89 #include <ShapeAnalysis_TransferParametersProj.hxx>
90 #include <ShapeAnalysis_Wire.hxx>
91 #include <ShapeAnalysis_WireOrder.hxx>
92 #include <ShapeBuild_Edge.hxx>
93 #include <ShapeBuild_ReShape.hxx>
94 #include <ShapeBuild_Vertex.hxx>
95 #include <ShapeConstruct_ProjectCurveOnSurface.hxx>
96 #include <ShapeExtend.hxx>
97 #include <ShapeExtend_WireData.hxx>
98 #include <ShapeFix.hxx>
99 #include <ShapeFix_Edge.hxx>
100 #include <ShapeFix_IntersectionTool.hxx>
101 #include <ShapeFix_SplitTool.hxx>
102 #include <ShapeFix_Wire.hxx>
103 #include <Standard_ErrorHandler.hxx>
104 #include <Standard_Failure.hxx>
105 #include <Standard_Type.hxx>
106 #include <TColgp_Array1OfPnt.hxx>
107 #include <TColgp_SequenceOfPnt.hxx>
108 #include <TColStd_Array1OfInteger.hxx>
109 #include <TColStd_Array1OfReal.hxx>
110 #include <TColStd_HSequenceOfReal.hxx>
111 #include <TopExp_Explorer.hxx>
112 #include <TopLoc_Location.hxx>
113 #include <TopoDS.hxx>
114 #include <TopoDS_Edge.hxx>
115 #include <TopoDS_Face.hxx>
116 #include <TopoDS_Vertex.hxx>
117 #include <TopoDS_Wire.hxx>
118 #include <TopTools_Array1OfShape.hxx>
119 #include <TopTools_HSequenceOfShape.hxx>
120
121 //S4135
122 //#######################################################################
123 //  Constructors, initializations, modes, querying
124 //#######################################################################
125 //=======================================================================
126 //function : ShapeFix_Wire
127 //purpose  : 
128 //=======================================================================
129 ShapeFix_Wire::ShapeFix_Wire() : myMaxTailAngleSine(0), myMaxTailWidth(-1)
130 {
131   myFixEdge = new ShapeFix_Edge;
132   myAnalyzer = new ShapeAnalysis_Wire;
133   ClearModes();
134   ClearStatuses();
135   myStatusRemovedSegment = Standard_False;
136 }
137
138 //=======================================================================
139 //function : ShapeFix_Wire
140 //purpose  : 
141 //=======================================================================
142
143 ShapeFix_Wire::ShapeFix_Wire (
144   const TopoDS_Wire& wire,
145   const TopoDS_Face &face,
146   const Standard_Real prec) : myMaxTailAngleSine(0), myMaxTailWidth(-1)
147 {
148   myFixEdge = new ShapeFix_Edge;
149   myAnalyzer = new ShapeAnalysis_Wire;
150   ClearModes();
151   SetMaxTolerance ( prec );
152   myStatusRemovedSegment = Standard_False;
153   Init ( wire, face, prec );
154 }
155
156 //=======================================================================
157 //function : SetPrecision
158 //purpose  : 
159 //=======================================================================
160
161 void ShapeFix_Wire::SetPrecision (const Standard_Real prec) 
162 {
163   ShapeFix_Root::SetPrecision ( prec );
164   myAnalyzer->SetPrecision ( prec );
165 }
166  
167 //=======================================================================
168 //function : SetMaxTailAngle
169 //purpose  :
170 //=======================================================================
171 void ShapeFix_Wire::SetMaxTailAngle(const Standard_Real theMaxTailAngle)
172 {
173   myMaxTailAngleSine = Sin(theMaxTailAngle);
174   myMaxTailAngleSine = (myMaxTailAngleSine >= 0) ? myMaxTailAngleSine : 0;
175 }
176
177 //=======================================================================
178 //function : SetMaxTailWidth
179 //purpose  :
180 //=======================================================================
181 void ShapeFix_Wire::SetMaxTailWidth(const Standard_Real theMaxTailWidth)
182 {
183   myMaxTailWidth = theMaxTailWidth;
184 }
185
186 //=======================================================================
187 //function : ClearModes
188 //purpose  : 
189 //=======================================================================
190
191 void ShapeFix_Wire::ClearModes()
192 {
193   myTopoMode = Standard_False;
194   myGeomMode = Standard_True;
195   myClosedMode = Standard_True;
196   myPreference2d = Standard_True;
197   myFixGapsByRanges = Standard_False;
198
199   myRemoveLoopMode = -1;
200
201   myFixReversed2dMode = -1;
202   myFixRemovePCurveMode = -1;
203   myFixRemoveCurve3dMode = -1;
204   myFixAddPCurveMode = -1;
205   myFixAddCurve3dMode = -1;
206   myFixSeamMode = -1;
207   myFixShiftedMode = -1;
208   myFixSameParameterMode = -1;
209   myFixVertexToleranceMode = -1;
210
211   myFixNotchedEdgesMode = -1;
212   myFixSelfIntersectingEdgeMode = -1;
213   myFixIntersectingEdgesMode = -1;
214   myFixNonAdjacentIntersectingEdgesMode = -1;
215   myFixTailMode = 0;
216
217   myFixReorderMode = -1;
218   myFixSmallMode = -1;
219   myFixConnectedMode = -1;
220   myFixEdgeCurvesMode = -1;
221   myFixDegeneratedMode = -1;
222   myFixSelfIntersectionMode = -1;
223   myFixLackingMode = -1;
224   myFixGaps3dMode = -1;
225   myFixGaps2dMode = -1;
226 }
227
228 //=======================================================================
229 //function : ClearStatuses
230 //purpose  : 
231 //=======================================================================
232
233 void ShapeFix_Wire::ClearStatuses()
234 {
235   Standard_Integer emptyStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
236
237   myLastFixStatus          = emptyStatus;
238
239   myStatusReorder          = emptyStatus;
240   myStatusSmall            = emptyStatus;
241   myStatusConnected        = emptyStatus;
242   myStatusEdgeCurves       = emptyStatus;
243   myStatusDegenerated      = emptyStatus;
244   myStatusSelfIntersection = emptyStatus;
245   myStatusLacking          = emptyStatus;
246   myStatusGaps3d           = emptyStatus; //szv#9:S4244:19Aug99 new method introduced
247   myStatusGaps2d           = emptyStatus; //szv#9:S4244:19Aug99 new method introduced
248   myStatusClosed           = emptyStatus;
249   myStatusNotches = emptyStatus;
250   myStatusFixTails = emptyStatus;
251 }
252
253 //=======================================================================
254 //function : Init
255 //purpose  : 
256 //=======================================================================
257
258 void ShapeFix_Wire::Init (const TopoDS_Wire& wire, 
259                           const TopoDS_Face &face, const Standard_Real prec) 
260 {
261   Load ( wire );
262   SetFace ( face );
263   SetPrecision ( prec );
264 }
265
266 //=======================================================================
267 //function : Init
268 //purpose  : 
269 //=======================================================================
270
271 void ShapeFix_Wire::Init (const Handle(ShapeAnalysis_Wire)& saw) 
272 {
273   ClearStatuses();
274   myAnalyzer = saw;
275   myShape.Nullify();
276 //  SetPrecision ( saw.Precision() );
277 }
278
279 //=======================================================================
280 //function : Load
281 //purpose  : 
282 //=======================================================================
283
284 void ShapeFix_Wire::Load (const TopoDS_Wire& wire) 
285 {
286   ClearStatuses();
287
288   TopoDS_Wire W = wire;
289   if ( ! Context().IsNull() ) {
290     TopoDS_Shape S = Context()->Apply ( wire );
291     W = TopoDS::Wire ( S );
292   }
293
294   myAnalyzer->Load ( W );
295   myShape = wire;
296 }
297
298 //=======================================================================
299 //function : Load
300 //purpose  : 
301 //=======================================================================
302
303 void ShapeFix_Wire::Load (const Handle(ShapeExtend_WireData)& sbwd) 
304 {
305   ClearStatuses();
306   myAnalyzer->Load ( sbwd );
307   if ( ! Context().IsNull() ) UpdateWire();
308   myShape.Nullify();
309 }
310
311 //=======================================================================
312 //function : NbEdges
313 //purpose  : 
314 //=======================================================================
315
316 Standard_Integer ShapeFix_Wire::NbEdges() const
317 {
318   Handle(ShapeExtend_WireData) sbwd = myAnalyzer->WireData();
319   return sbwd.IsNull() ? 0 : sbwd->NbEdges();
320 }
321
322 //#######################################################################
323 //  Fixing methods of API level
324 //#######################################################################
325   
326 //=======================================================================
327 //function : Perform
328 //purpose  : This method performs all the available fixes.
329 //           If some fix is turned on or off explicitly by the flag,
330 //           it is called or not depending on that flag
331 //           Else (i.e. if flag is default) fix is called depending on the 
332 //           situation: default is True, but some fixes are not called or
333 //           are limited if order of edges in the wire is not OK
334 //=======================================================================
335
336 Standard_Boolean ShapeFix_Wire::Perform() 
337 {
338   ClearStatuses();
339   if ( ! IsLoaded() ) return Standard_False;
340   
341
342   Standard_Integer Fixed = Standard_False;
343   
344   // FixReorder is first, because as a rule wire is required to be ordered
345   // We shall analyze the order of edges in the wire and set appropriate 
346   // status even if FixReorder should not be called (if it is forbidden)
347
348   ShapeAnalysis_WireOrder sawo;
349   Standard_Boolean ReorderOK = ( myAnalyzer->CheckOrder ( sawo, myClosedMode ) ==0 );
350   if ( NeedFix ( myFixReorderMode, ! ReorderOK ) ) { 
351     if(FixReorder()) Fixed = Standard_True; 
352     ReorderOK = ! StatusReorder ( ShapeExtend_FAIL );
353   }
354
355   // FixSmall is allowed to change topology only if mode is set and FixReorder 
356   // did not failed
357   if ( NeedFix ( myFixSmallMode, myTopoMode ) ) {
358     if ( FixSmall ( ! myTopoMode || ! ReorderOK, MinTolerance() ) ) {
359       Fixed = Standard_True;
360       // retry reorder if necessary (after FixSmall it can work better)
361       if ( NeedFix ( myFixReorderMode, ! ReorderOK ) ) { 
362         FixReorder();
363         ReorderOK = ! StatusReorder ( ShapeExtend_FAIL );
364       }
365     }
366   }
367
368   if ( NeedFix ( myFixConnectedMode, ReorderOK ) ) {
369     if ( FixConnected() ) Fixed = Standard_True;
370   }
371
372   if ( NeedFix ( myFixEdgeCurvesMode ) ) {
373     Standard_Integer savFixShiftedMode = myFixShiftedMode;
374     // turn out FixShifted if reorder not done
375     if ( myFixShiftedMode == -1 && ! ReorderOK ) myFixShiftedMode = 0; 
376     if ( FixEdgeCurves() ) Fixed = Standard_True;
377     myFixShiftedMode = savFixShiftedMode;
378   }
379   
380   if ( NeedFix ( myFixDegeneratedMode ) ) {
381     if ( FixDegenerated() ) Fixed = Standard_True; // ?? if ! ReorderOK ??
382   }
383   
384   //pdn - temporary to test
385   if (myFixTailMode <= 0 && NeedFix(myFixNotchedEdgesMode, ReorderOK))
386   {
387     Fixed |= FixNotchedEdges();
388     if(Fixed) FixShifted(); //skl 07.03.2002 for OCC180
389   }
390     
391   if (myFixTailMode != 0)
392   {
393     Fixed |= FixTails();
394     if (Fixed)
395     {
396       FixShifted();
397     }
398   }
399
400   if ( NeedFix ( myFixSelfIntersectionMode, myClosedMode ) ) {
401     Standard_Integer savFixIntersectingEdgesMode = myFixIntersectingEdgesMode;
402     // switch off FixIntEdges if reorder not done
403     if ( myFixIntersectingEdgesMode == -1 && ! ReorderOK ) 
404          myFixIntersectingEdgesMode = 0; 
405     if ( FixSelfIntersection() ) Fixed = Standard_True;
406     FixReorder();
407     myFixIntersectingEdgesMode = savFixIntersectingEdgesMode;
408   }
409
410   if ( NeedFix ( myFixLackingMode, ReorderOK ) ) {
411     if ( FixLacking() ) Fixed = Standard_True;
412   }
413
414   // TEMPORARILY without special mode !!!
415   Handle(ShapeExtend_WireData) sbwd = WireData();
416   for (Standard_Integer iedge = 1; iedge <= sbwd->NbEdges(); iedge++)
417     if ( myFixEdge->FixVertexTolerance (sbwd->Edge (iedge)) ) 
418       Fixed = Standard_True;
419
420   return Fixed;
421 }
422
423 //=======================================================================
424 //function : FixReorder
425 //purpose  : 
426 //=======================================================================
427
428 Standard_Boolean ShapeFix_Wire::FixReorder() 
429 {
430   myStatusReorder = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
431   if ( ! IsLoaded() ) return Standard_False;
432
433   // fix in 3d
434   ShapeAnalysis_WireOrder sawo;
435   myAnalyzer->CheckOrder ( sawo, myClosedMode, Standard_True );
436   
437   //:abv revolCuts.sat -23: in case of bi-periodic surface check case
438   // of reversed wire specifically. This is necessary because degenerated
439   // cases are possible when direct evaluation will give bad result.
440   Standard_Boolean isReorder = Standard_False;
441   if ( sawo.Status() != 0 &&
442        ! myAnalyzer->Surface().IsNull() &&
443        myAnalyzer->Surface()->Surface()->IsUPeriodic() &&
444        myAnalyzer->Surface()->Surface()->IsVPeriodic() ) {
445     Handle(ShapeExtend_WireData) sbwd2 = new ShapeExtend_WireData;
446     for ( Standard_Integer i=WireData()->NbEdges(); i >=1; i-- )
447       sbwd2->Add ( WireData()->Edge(i) );
448     ShapeAnalysis_WireOrder sawo2;
449     ShapeAnalysis_Wire analyzer2 ( sbwd2, myAnalyzer->Face(), Precision() );
450     analyzer2.CheckOrder ( sawo2, myClosedMode, Standard_True );
451     if ( ( sawo2.Status() >=0 && sawo2.Status() < sawo.Status() ) || 
452          ( sawo.Status()   <0 && sawo2.Status() > sawo.Status() ) ) {
453       WireData()->Init ( sbwd2 );
454       sawo = sawo2;
455       isReorder = Standard_True;
456     }
457   }
458   
459   FixReorder ( sawo );
460   
461   if ( LastFixStatus ( ShapeExtend_FAIL ) )
462     myStatusReorder |= ShapeExtend::EncodeStatus ( LastFixStatus ( ShapeExtend_FAIL1 ) ? 
463                                                  ShapeExtend_FAIL1 : ShapeExtend_FAIL2 );
464   if ( ! LastFixStatus ( ShapeExtend_DONE )&& !isReorder ) return Standard_False;
465   
466   myStatusReorder |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
467   if ( sawo.Status() ==2 || sawo.Status() ==-2 ) 
468     myStatusReorder |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
469   if ( sawo.Status() <0 ) 
470     myStatusReorder |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
471   if ( sawo.Status() == 3)
472     myStatusReorder |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );//only shifted
473   return Standard_True;
474 }
475
476 //=======================================================================
477 //function : FixSmall
478 //purpose  : 
479 //=======================================================================
480
481 Standard_Integer ShapeFix_Wire::FixSmall (const Standard_Boolean lockvtx,
482                                              const Standard_Real precsmall) 
483 {
484   myStatusSmall = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
485   if ( ! IsLoaded() ) return Standard_False;
486   
487   for ( Standard_Integer i = NbEdges(); i >0; i-- ) {
488     FixSmall ( i, lockvtx, precsmall );
489     myStatusSmall |= myLastFixStatus;
490   }
491
492   return StatusSmall ( ShapeExtend_DONE );
493
494 }
495
496 //=======================================================================
497 //function : FixConnected
498 //purpose  : 
499 //=======================================================================
500
501 Standard_Boolean ShapeFix_Wire::FixConnected (const Standard_Real prec) 
502 {
503   myStatusConnected = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
504   if ( ! IsLoaded() ) return Standard_False;
505   
506   Standard_Integer stop = ( myClosedMode ? 0 : 1 );
507   for ( Standard_Integer i = NbEdges(); i > stop; i-- ) {
508     FixConnected ( i, prec );
509     myStatusConnected |= myLastFixStatus;
510   }
511
512   return StatusConnected ( ShapeExtend_DONE );
513 }
514
515 //=======================================================================
516 //function : FixEdgeCurves
517 //purpose  : 
518 //=======================================================================
519
520 Standard_Boolean ShapeFix_Wire::FixEdgeCurves() 
521 {
522   myStatusEdgeCurves = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
523   if ( ! IsLoaded() ) return Standard_False;
524   Standard_Boolean isReady = IsReady();
525
526   Handle(ShapeExtend_WireData) sbwd = WireData();
527   Standard_Integer i, nb = sbwd->NbEdges();
528   TopoDS_Face face = Face();
529   Handle(ShapeFix_Edge) theAdvFixEdge = Handle(ShapeFix_Edge)::DownCast(myFixEdge);
530   if (theAdvFixEdge.IsNull()) myFixReversed2dMode = Standard_False;
531
532   // fix revesred 2d / 3d curves
533   if ( isReady && NeedFix ( myFixReversed2dMode ) ) {
534     for ( i=1; i <= nb; i++ ) {
535       theAdvFixEdge->FixReversed2d ( sbwd->Edge(i), face ); 
536       if ( theAdvFixEdge->Status ( ShapeExtend_DONE ) ) 
537         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
538       if ( theAdvFixEdge->Status ( ShapeExtend_FAIL ) ) 
539         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
540     }
541   }
542   
543   // add / remove pcurve
544   if ( isReady && NeedFix ( myFixRemovePCurveMode, Standard_False ) ) {
545     for ( i=1; i <= nb; i++ ) {
546       myFixEdge->FixRemovePCurve ( sbwd->Edge(i), face );
547       if ( myFixEdge->Status ( ShapeExtend_DONE ) ) 
548         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
549       if ( myFixEdge->Status ( ShapeExtend_FAIL ) ) 
550         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
551     }
552   }
553
554   if ( isReady && NeedFix ( myFixAddPCurveMode ) ) {
555     Standard_Integer overdegen = 0; //:c0
556     for ( i=1; i <= nb; i++ ) {
557       myFixEdge->FixAddPCurve ( sbwd->Edge(i), face, sbwd->IsSeam(i), 
558                          myAnalyzer->Surface(), Precision() );
559       if ( myFixEdge->Status ( ShapeExtend_DONE ) ) 
560         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
561       if ( myFixEdge->Status ( ShapeExtend_FAIL ) ) 
562         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL3 );
563
564       //if ( !sbwd->IsSeam(i) && myFixEdge->Status ( ShapeExtend_DONE2 )
565       //     && BRep_Tool::SameParameter(sbwd->Edge(i)) ) {
566       if ( !sbwd->IsSeam(i) && myFixEdge->Status ( ShapeExtend_DONE2 ) ) {
567         // abv 24 Feb 00: trj3_s1-ac-214.stp #1631 etc.: try to split the edge in singularity
568         if ( ! Context().IsNull() ) { 
569           ShapeBuild_Edge sbe;
570           TopoDS_Edge E = sbwd->Edge ( i );
571           ShapeAnalysis_Curve SAC;
572           Standard_Real a, b;
573           Handle(Geom_Curve) C = BRep_Tool::Curve ( E, a, b );
574           Handle(ShapeAnalysis_Surface) S = myAnalyzer->Surface();
575           Standard_Integer nbs = S->NbSingularities(MinTolerance());
576           GeomAdaptor_Curve GAC ( C, a, b );
577           TColStd_SequenceOfReal seq;
578           for (Standard_Integer j=1; j <= nbs; j++) {
579             Standard_Real Preci;
580             gp_Pnt2d pd1, pd2;
581             gp_Pnt P3d, pr;
582             Standard_Real par1, par2, split;
583             Standard_Boolean tmpUIsoDeg;
584             S->Singularity (j, Preci, P3d, pd1, pd2, par1, par2, tmpUIsoDeg);
585             if ( SAC.Project ( GAC, P3d, MinTolerance(), pr, split, Standard_True ) < Max(Preci,MinTolerance()) ) {
586               if ( split - a > ::Precision::PConfusion() &&
587                    b - split > ::Precision::PConfusion() ) {
588                 Standard_Integer k;
589                 for ( k=1; k <= seq.Length(); k++ ) {
590                   if ( split < seq(k)-::Precision::PConfusion() ) {
591                     seq.InsertBefore ( k, split );
592                     break;
593                   }
594                   else if ( split < seq(k)+::Precision::PConfusion() ) break;
595                 }
596                 if ( k > seq.Length() ) seq.Append ( split );
597               }
598             }
599           }
600           if ( seq.Length() >0 ) { // supposed that edge is SP
601 #ifdef OCCT_DEBUG
602             cout << "Edge going over singularity detected; splitted" << endl;
603 #endif
604       Standard_Boolean isFwd = ( E.Orientation() == TopAbs_FORWARD );
605       E.Orientation ( TopAbs_FORWARD );
606
607       //if( BRep_Tool::SameParameter(sbwd->Edge(i)) )
608       //  sbe.RemovePCurve ( E, face );
609
610       //10.04.2003 skl for using trimmed lines as pcurves
611       ShapeAnalysis_Edge sae;
612       if( BRep_Tool::SameParameter(sbwd->Edge(i)) )
613         sbe.RemovePCurve ( E, face );
614       else {
615         if(sae.HasPCurve(E,face)) {
616           Handle(Geom2d_Curve) C2d;
617           Standard_Real fp2d,lp2d;
618           if(sae.PCurve(E,face,C2d,fp2d,lp2d)) {
619             if( !C2d->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)) )
620               sbe.RemovePCurve(E,face);
621           }
622         }
623       }
624
625 //    myFixEdge->FixSameParameter ( E ); // to ensure SameRange & SP
626       BRep_Builder B;
627       TopoDS_Vertex V1, V2, V;
628       //ShapeAnalysis_Edge sae;
629       V1 = sae.FirstVertex ( E );
630       V2 = sae.LastVertex ( E );
631         
632       Handle(ShapeExtend_WireData) sw = new ShapeExtend_WireData;
633       for ( Standard_Integer k=0; k <= seq.Length(); k++ )
634       {
635         Standard_Real split = ( k < seq.Length() ? seq(k+1) : b );
636         if ( k < seq.Length() )
637         {
638           B.MakeVertex ( V, C->Value(split), BRep_Tool::Tolerance(E) );
639           //try increase tolerance before splitting
640           Standard_Real aDist = BRep_Tool::Pnt(V1).Distance(BRep_Tool::Pnt(V));
641           if (aDist < BRep_Tool::Tolerance(V1) * 1.01) {
642             B.UpdateVertex(V1, Max(aDist, BRep_Tool::Tolerance(V1)));
643             a = split;
644             V1 = V;
645             continue;
646           }
647           else
648           {
649             aDist = BRep_Tool::Pnt(V2).Distance(BRep_Tool::Pnt(V));
650             if (aDist < BRep_Tool::Tolerance(V2) * 1.01) {
651               B.UpdateVertex(V, Max(aDist, BRep_Tool::Tolerance(V2)));
652               b = split;
653               V2 = V;
654               continue;
655             }
656           }
657         }
658         else
659         {
660           V = V2;
661         }
662
663         TopoDS_Edge edge = sbe.CopyReplaceVertices ( E, V1, V );
664         if( BRep_Tool::SameParameter(sbwd->Edge(i)) ) {
665           //TopoDS_Edge edge = sbe.CopyReplaceVertices ( E, V1, V );
666           B.Range ( edge, a, split );
667           sw->Add ( edge );
668         }
669         else {
670           //TopoDS_Edge edge = sbe.CopyReplaceVertices(sbwd->Edge(i),V1,V);
671           Handle(ShapeAnalysis_TransferParameters) sftp =
672             new ShapeAnalysis_TransferParameters(E,face);
673           sftp->TransferRange(edge, a, split, Standard_False);
674           sw->Add(edge);
675         }
676         //sw->Add(edge);
677         a = split;
678         V1 = V;
679       }
680       if ( ! isFwd ) {
681         sw->Reverse();
682         E.Orientation ( TopAbs_REVERSED );
683       }
684       Context()->Replace ( E, sw->Wire() );
685       UpdateWire();
686       nb = sbwd->NbEdges();
687       i--;
688       continue;
689     }
690         }
691         
692         overdegen = i;
693       }
694     }
695
696     //:c0 abv 20 Feb 98: treat case of curve going over degenerated pole and seam
697     if ( overdegen && myAnalyzer->Surface()->IsUClosed(Precision()) ) {
698       ShapeBuild_Edge sbe;
699       Standard_Real URange, SUF, SUL, SVF, SVL;
700       myAnalyzer->Surface()->Bounds(SUF, SUL, SVF, SVL);
701       URange = (Abs(SUL - SUF));
702       gp_XY vec(0,0);
703       ShapeAnalysis_Edge sae;
704       Standard_Integer k;
705       for ( k = 1; k <= nb; k++) {
706         Standard_Real cf, cl;
707         Handle(Geom2d_Curve) c2d;
708         if ( ! sae.PCurve ( sbwd->Edge(k), face, c2d, cf, cl, Standard_True ) ) break;
709         vec += c2d->Value(cl).XY() - c2d->Value(cf).XY();
710       }
711       if ( k > nb && Abs ( Abs ( vec.X() ) - URange ) < 0.1 * URange ) {
712         sbe.RemovePCurve (sbwd->Edge ( overdegen ), face);
713         myFixEdge->Projector()->AdjustOverDegenMode() = Standard_False;
714         myFixEdge->FixAddPCurve ( sbwd->Edge(overdegen), face, sbwd->IsSeam(overdegen), myAnalyzer->Surface(), Precision());
715       }
716 #ifdef OCCT_DEBUG
717       cout << "Edge going over singularity detected; pcurve adjusted" << endl;
718 #endif
719     }
720   }
721
722   // add / remove pcurve
723   if ( isReady && NeedFix ( myFixRemoveCurve3dMode, Standard_False ) ) {
724     for ( i=1; i <= nb; i++ ) {
725       myFixEdge->FixRemoveCurve3d ( sbwd->Edge(i) );
726       if ( myFixEdge->Status ( ShapeExtend_DONE ) ) 
727         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
728       if ( myFixEdge->Status ( ShapeExtend_FAIL ) ) 
729         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL4 );
730     }
731   }
732   if ( NeedFix ( myFixAddCurve3dMode ) ) {
733     for ( i=1; i <= nb; i++ ) {
734       myFixEdge->FixAddCurve3d ( sbwd->Edge(i) );
735       if ( myFixEdge->Status ( ShapeExtend_DONE ) ) 
736         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
737       if ( myFixEdge->Status ( ShapeExtend_FAIL ) ) {
738         //:abv 29.08.01: Spatial_firex_lofting.sat: if 3d curve cannot
739         // be built because edge has no pcurves either, remove that edge
740         Handle(Geom2d_Curve) C;
741         Handle(Geom_Surface) S;
742         TopLoc_Location L;
743         Standard_Real first = 0., last = 0.;
744         BRep_Tool::CurveOnSurface ( sbwd->Edge(i), C, S, L, first, last );
745         if ( C.IsNull() || Abs (last - first) < Precision::PConfusion())
746         {
747           SendWarning ( sbwd->Edge ( i ), Message_Msg ( "FixWire.FixCurve3d.Removed" ) );// Incomplete edge (with no pcurves or 3d curve) removed
748           sbwd->Remove ( i-- );
749           nb--;
750           myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
751           FixConnected (i + 1, Precision());
752         }
753         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL5 );
754       }
755     }
756   }
757   
758   // fix seam
759   if ( isReady && NeedFix ( myFixSeamMode, Standard_False ) ) {
760     for ( i=1; i <= nb; i++ ) {
761       FixSeam ( i );
762       if ( LastFixStatus ( ShapeExtend_DONE ) ) 
763         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE6 );
764       if ( LastFixStatus ( ShapeExtend_FAIL ) ) 
765         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL6 );
766     }
767   }
768
769   // fix shifted
770   if ( isReady && NeedFix ( myFixShiftedMode ) ) {
771     FixShifted();
772     if ( LastFixStatus ( ShapeExtend_DONE ) ) 
773       myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
774     if ( LastFixStatus ( ShapeExtend_FAIL ) ) 
775       myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL7 );
776   }
777
778   // fix same parameter
779   if ( isReady && NeedFix ( myFixSameParameterMode ) ) {
780     for ( i=1; i <= nb; i++ ) {
781       // skl 28.10.2004 for OCC6366 - check SameRange
782       ShapeAnalysis_Edge sae;
783       Standard_Real First, Last;
784       Handle(Geom_Curve) tmpc3d = BRep_Tool::Curve(sbwd->Edge(i), First, Last);
785       if(sae.HasPCurve(sbwd->Edge(i),face)) {
786         Handle(Geom2d_Curve) C2d;
787         Standard_Real fp2d,lp2d;
788         if(sae.PCurve(sbwd->Edge(i),face,C2d,fp2d,lp2d)) {
789           if( fabs(First-fp2d)>Precision::PConfusion() ||
790               fabs(Last-lp2d)>Precision::PConfusion() ) {
791             BRep_Builder B;
792             B.SameRange(sbwd->Edge(i),Standard_False);
793           }
794         }
795       }
796       myFixEdge->FixSameParameter ( sbwd->Edge(i) );
797       if ( myFixEdge->Status ( ShapeExtend_DONE ) ) 
798         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
799       if ( myFixEdge->Status ( ShapeExtend_FAIL ) ) 
800         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL8 );
801     }
802   }
803     
804   //:abv 10.06.02: porting C40 -> dev (CC670-12608.stp): moved from Perform()
805   // Update with face is needed for plane surfaces (w/o stored pcurves)
806   if ( NeedFix ( myFixVertexToleranceMode ) ) {
807     for ( i=1; i <= nb; i++) {
808       myFixEdge->FixVertexTolerance (sbwd->Edge (i), face);
809       if ( myFixEdge->Status ( ShapeExtend_DONE ) ) 
810         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
811       if ( myFixEdge->Status ( ShapeExtend_FAIL ) ) 
812         myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL8 );
813     }
814   }
815   
816   return StatusEdgeCurves ( ShapeExtend_DONE );
817 }
818
819 //=======================================================================
820 //function : FixDegenerated
821 //purpose  : 
822 //=======================================================================
823
824 Standard_Boolean ShapeFix_Wire::FixDegenerated() 
825 {
826   myStatusDegenerated = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
827   if ( ! IsReady() ) return Standard_False;
828   
829 //  if ( ! myAnalyzer->Surface()->HasSingularities ( Precision() ) ) return;
830
831   Standard_Integer lastcoded = -1, prevcoded = 0;
832   Standard_Integer stop = ( myClosedMode ? 0 : 1 );
833   for ( Standard_Integer i = NbEdges(); i > stop; i-- ) {
834     FixDegenerated ( i );
835     myStatusDegenerated |= myLastFixStatus;
836     //:r0 abv 19 Mar 99: PRO7226.stp #489490: remove duplicated degenerated edges
837     Standard_Integer coded = ( LastFixStatus ( ShapeExtend_DONE2 ) ? 1 : 0 );
838     if ( lastcoded ==-1 ) lastcoded = coded;
839     if ( coded && ( prevcoded || ( i ==1 && lastcoded ) ) && NbEdges() >1 ) {
840       Handle(ShapeExtend_WireData) sbwd = WireData();
841       BRep_Builder B;
842       sbwd->Remove ( i );
843       if ( ! prevcoded ) i = NbEdges();
844       B.Degenerated ( sbwd->Edge ( i++ ), Standard_False );
845       prevcoded = 0;
846     }
847     else prevcoded = coded; 
848   }
849
850   return StatusDegenerated ( ShapeExtend_DONE );
851 }
852
853
854 //=======================================================================
855 //function : FixSelfIntersection
856 //purpose  : Applies FixSelfIntersectingEdge and FixIntersectingEdges
857 //           and removes wrong edges
858 //=======================================================================
859
860 Standard_Boolean ShapeFix_Wire::FixSelfIntersection() 
861 {
862   myStatusSelfIntersection = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
863   if ( ! IsReady() ) return Standard_False;
864
865   Handle(ShapeExtend_WireData) sbwd = WireData();
866   Standard_Integer nb = sbwd->NbEdges();
867   
868   if ( NeedFix ( myFixSelfIntersectingEdgeMode ) ) {
869     if (myRemoveLoopMode<1)
870       for ( Standard_Integer num=1; num <=nb; num++ ) 
871       {
872         FixSelfIntersectingEdge ( num );
873         myStatusSelfIntersection |= myLastFixStatus;
874       }
875     else if (myRemoveLoopMode==1)
876     {
877       for ( Standard_Integer num=1; num <=nb; num++ )
878       {
879         FixSelfIntersectingEdge ( num );
880         myStatusSelfIntersection |= myLastFixStatus;
881         if(nb<sbwd->NbEdges()) num--;
882         nb = sbwd->NbEdges();
883       }
884       FixClosed(Precision());
885     }
886   }
887   
888   if ( NeedFix ( myFixIntersectingEdgesMode ) ) {
889     Standard_Integer num = ( myClosedMode ? 1 : 2 );
890     for ( ; nb >1 && num <= nb; num++ ) {
891       FixIntersectingEdges ( num );
892       if ( LastFixStatus ( ShapeExtend_FAIL1 ) ) 
893         myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
894       if ( LastFixStatus ( ShapeExtend_FAIL2 ) ) 
895         myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
896       if ( ! LastFixStatus ( ShapeExtend_DONE ) ) continue;
897
898       if ( LastFixStatus ( ShapeExtend_DONE1 ) ) 
899         myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
900       if ( LastFixStatus ( ShapeExtend_DONE2 ) ) 
901         myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
902       if(LastFixStatus (ShapeExtend_DONE6))
903   myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE6 );
904
905       if ( /*! myTopoMode ||*/ nb < 3 ) {
906         //#86 rln 22.03.99 sim2.igs, entity 4292: After fixing of self-intersecting
907         //BRepCheck finds one more self-intersection not found by ShapeAnalysis
908         //%15 pdn 06.04.99 repeat until fixed CTS18546-2 entity 777
909         
910         // if the tolerance was modified we should recheck the result, if it was enough
911         if ( LastFixStatus ( ShapeExtend_DONE7 ) ) num--;
912         continue;
913       }
914
915       if ( LastFixStatus ( ShapeExtend_DONE4 ) ) sbwd->Remove ( num );
916       if ( LastFixStatus ( ShapeExtend_DONE3 ) ) sbwd->Remove ( num >1 ? num-1 : nb+num-1 );
917       if ( LastFixStatus ( ShapeExtend_DONE4 ) ||
918            LastFixStatus ( ShapeExtend_DONE3 ) ) {
919         myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
920         num = ( myClosedMode ? 1 : 2 );
921         nb = sbwd->NbEdges();
922 #ifdef OCCT_DEBUG
923         cout << "Warning: ShapeFix_Wire::FixSelfIntersection: Edge removed" << endl;
924 #endif
925       }
926       else {
927         //#86 rln 22.03.99
928         //%15 pdn 06.04.99 repeat until fixed CTS18546-2 entity 777
929         //FixIntersectingEdges ( num );
930         /*if ( LastFixStatus ( ShapeExtend_DONE7 ) )*/
931         // Always revisit the fixed edge
932         num--;
933       }
934     }
935   }
936   
937   //pdn 17.03.99 S4135 to avoid regression fixing not adjacent intersection
938   if ( NeedFix ( myFixNonAdjacentIntersectingEdgesMode ) ) {
939
940     ShapeFix_IntersectionTool ITool(Context(),Precision());
941     Standard_Integer NbSplit=0, NbCut=0,NbRemoved=0;
942     if(ITool.FixSelfIntersectWire(sbwd,myAnalyzer->Face(),NbSplit,NbCut,NbRemoved)) {
943       myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );//gka 06.09.04
944     }
945     if( NbSplit>0 || NbRemoved>0 ) {
946       if(NbRemoved>0) myStatusRemovedSegment = Standard_True;
947       //Load(sbwd); commented by skl 29.12.2004 for OCC7624, instead this
948       //            string inserted following three strings:
949       myAnalyzer->Load ( sbwd );
950       if ( ! Context().IsNull() ) UpdateWire();
951       myShape.Nullify();
952     }
953 #ifdef OCCT_DEBUG
954     if (StatusSelfIntersection (ShapeExtend_DONE5))
955       cout<<"Warning: ShapeFix_Wire::FixIntersection: Non-adjacent intersection fixed (split-"
956         <<NbSplit<<", cut-"<<NbCut<<", removed-"<<NbRemoved<<")"<<endl;
957 #endif    
958
959 /*
960     Bnd_Array1OfBox2d boxes(1,nb);
961     TopLoc_Location L;
962     const Handle(Geom_Surface)& S = BRep_Tool::Surface(Face(), L);
963     Handle(Geom2d_Curve) c2d;
964     Standard_Real cf,cl;
965     ShapeAnalysis_Edge sae;
966     for(Standard_Integer i = 1; i <= nb; i++){
967       TopoDS_Edge E = sbwd->Edge (i);
968       if(sae.PCurve (E,S,L,c2d,cf,cl,Standard_False)) {
969         Bnd_Box2d box;
970         Geom2dAdaptor_Curve gac;
971         Standard_Real aFirst = c2d->FirstParameter();
972         Standard_Real aLast = c2d->LastParameter();
973         if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) 
974            && (cf < aFirst || cl > aLast)) {
975           //pdn avoiding problems with segment in Bnd_Box
976           gac.Load(c2d);
977         }
978         else
979           gac.Load(c2d,cf,cl);
980         BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
981         boxes(i) = box;
982       }
983     }
984     
985     Standard_Boolean isFail = Standard_False, isDone = Standard_False;
986     for(Standard_Integer num1 = 1; num1 < nb-1; num1++) {
987       Standard_Integer fin = (num1 == 1 ? nb-1 : nb);
988       for(Standard_Integer num2 = num1+2; num2 <= fin; num2++) 
989         if(!boxes(num1).IsOut(boxes(num2))){
990           FixIntersectingEdges (num1, num2);
991           isFail |= LastFixStatus ( ShapeExtend_FAIL1 );
992           isDone |= LastFixStatus ( ShapeExtend_DONE1 );
993         }
994     }
995     
996     if(isFail)
997       myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL3 );
998     if(isDone)
999       myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
1000 #ifdef OCCT_DEBUG
1001     if (StatusSelfIntersection (ShapeExtend_DONE5))
1002       cout << "Warning: ShapeFix_Wire::FixSelfIntersection: Non ajacent intersection fixed" << endl;
1003 #endif    
1004 */
1005   }
1006
1007   return StatusSelfIntersection ( ShapeExtend_DONE );
1008 }
1009
1010
1011 //=======================================================================
1012 //function : FixLacking
1013 //purpose  : 
1014 //=======================================================================
1015
1016 Standard_Boolean ShapeFix_Wire::FixLacking ( const Standard_Boolean force ) 
1017 {
1018   myStatusLacking = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
1019   if ( ! IsReady() ) return Standard_False;
1020   
1021   Standard_Integer start = ( myClosedMode ? 1 : 2 );
1022   for ( Standard_Integer i = start; i <= NbEdges(); i++ ) {
1023     FixLacking ( i, force );
1024     myStatusLacking |= myLastFixStatus;
1025   }
1026   
1027   return StatusLacking ( ShapeExtend_DONE );
1028 }
1029
1030
1031 //=======================================================================
1032 //function : FixClosed
1033 //purpose  : 
1034 //=======================================================================
1035
1036 Standard_Boolean ShapeFix_Wire::FixClosed (const Standard_Real prec) 
1037 {
1038   myStatusClosed = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
1039   if ( ! IsLoaded() || NbEdges() <1 ) return Standard_False;
1040   
1041   FixConnected ( 1, prec );
1042   if ( LastFixStatus ( ShapeExtend_DONE ) ) 
1043     myStatusClosed |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
1044   if ( LastFixStatus ( ShapeExtend_FAIL ) ) 
1045     myStatusClosed |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
1046
1047   FixDegenerated ( 1 );
1048   if ( LastFixStatus ( ShapeExtend_DONE ) ) 
1049     myStatusClosed |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
1050   if ( LastFixStatus ( ShapeExtend_FAIL ) ) 
1051     myStatusClosed |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
1052
1053   FixLacking ( 1 );
1054   if ( LastFixStatus ( ShapeExtend_DONE ) ) 
1055     myStatusClosed |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
1056   if ( LastFixStatus ( ShapeExtend_FAIL ) ) 
1057     myStatusClosed |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL3 );
1058   
1059   return StatusClosed ( ShapeExtend_DONE );
1060 }
1061
1062
1063 //#######################################################################
1064 //  Fixing methods of advanced level
1065 //#######################################################################
1066   
1067 //=======================================================================
1068 //function : FixReorder
1069 //purpose  : 
1070 //=======================================================================
1071
1072 Standard_Boolean ShapeFix_Wire::FixReorder (const ShapeAnalysis_WireOrder& wi) 
1073 {
1074   myLastFixStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
1075   if ( ! IsLoaded() ) return Standard_False;
1076   
1077   Standard_Integer status = wi.Status();
1078   if ( status ==0 ) return Standard_False;
1079   if ( status <=-10 ) {
1080     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
1081     return Standard_False;
1082   }
1083
1084   Handle(ShapeExtend_WireData) sbwd = WireData();
1085   Standard_Integer i, nb = sbwd->NbEdges();
1086   if ( nb != wi.NbEdges() ) {  
1087     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
1088     return Standard_False;  
1089   }
1090   // D abord on protege
1091   for (i = 1; i <= nb; i ++) {
1092     if ( wi.Ordered(i) == 0 ) {  
1093       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL3 );
1094       return Standard_False;  
1095     }
1096   }
1097
1098   Handle(TopTools_HSequenceOfShape) newedges = new TopTools_HSequenceOfShape();
1099   for ( i=1; i <= nb; i++ )
1100     newedges->Append ( sbwd->Edge ( wi.Ordered(i) ) );
1101   for ( i=1; i <= nb; i++ ) 
1102     sbwd->Set ( TopoDS::Edge ( newedges->Value(i) ), i );
1103   
1104   myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
1105   return Standard_True;
1106 }
1107
1108
1109 //=======================================================================
1110 //function : FixSmall
1111 //purpose  : 
1112 //=======================================================================
1113
1114 Standard_Boolean ShapeFix_Wire::FixSmall (const Standard_Integer num,
1115                                           const Standard_Boolean lockvtx,
1116                                           const Standard_Real precsmall) 
1117 {
1118   myLastFixStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
1119   if ( ! IsLoaded() || NbEdges() <=1 ) return Standard_False;
1120
1121   // analysis:
1122   Handle(ShapeAnalysis_Wire) theAdvAnalyzer = Handle(ShapeAnalysis_Wire)::DownCast(myAnalyzer);
1123   if (theAdvAnalyzer.IsNull()) return Standard_False;
1124   Standard_Integer n = ( num >0 ? num : NbEdges() );
1125   theAdvAnalyzer->CheckSmall ( n, precsmall );
1126   if ( theAdvAnalyzer->LastCheckStatus ( ShapeExtend_FAIL ) ) {
1127     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
1128 //:n2    return Standard_False;
1129   }
1130
1131   if ( ! theAdvAnalyzer->LastCheckStatus ( ShapeExtend_DONE ) ) return Standard_False;
1132
1133   // OUI cette edge est NULLE
1134
1135   if ( theAdvAnalyzer->LastCheckStatus ( ShapeExtend_DONE2 ) ) {
1136     // edge is small, but vertices are not the same..
1137     if ( lockvtx || ! myTopoMode ) {
1138       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
1139       return Standard_False;
1140     }
1141     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
1142   }
1143   else myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
1144
1145   // action: remove edge
1146   if ( ! Context().IsNull() ) 
1147     Context()->Remove(WireData()->Edge(n));
1148   SendWarning ( WireData()->Edge ( n ), Message_Msg ( "FixAdvWire.FixSmall.MSG0" ) ); //Small edge(s) removed
1149   WireData()->Remove ( n );
1150   
1151   // call FixConnected in the case if vertices of the small edge were not the same
1152   if ( LastFixStatus ( ShapeExtend_DONE2 ) ) {
1153     Standard_Integer savLastFixStatus = myLastFixStatus;
1154     //#43 rln 20.11.98 S4054 CTS18544 entity 21734 removing last edge
1155     FixConnected ( n <= NbEdges() ? n : 1, precsmall );
1156     if ( LastFixStatus ( ShapeExtend_FAIL ) )
1157       savLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL3 );
1158     myLastFixStatus = savLastFixStatus;
1159   }
1160
1161   return Standard_True;
1162 }
1163
1164
1165 //=======================================================================
1166 //function : FixConnected
1167 //purpose  : 
1168 //=======================================================================
1169
1170 Standard_Boolean ShapeFix_Wire::FixConnected (const Standard_Integer num,
1171                                               const Standard_Real prec) 
1172 {
1173   myLastFixStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
1174   if ( ! IsLoaded() || NbEdges() <=0 ) return Standard_False;
1175
1176   // analysis
1177   
1178   myAnalyzer->CheckConnected ( num, prec < 0 ? MaxTolerance() : prec );
1179   if ( myAnalyzer->LastCheckStatus ( ShapeExtend_FAIL ) ) {
1180     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
1181   }
1182   if ( ! myAnalyzer->LastCheckStatus ( ShapeExtend_DONE ) ) return Standard_False;
1183
1184   // action: replacing vertex
1185   
1186   Handle(ShapeExtend_WireData) sbwd = WireData();
1187   Standard_Integer n2 = ( num >0 ? num  : sbwd->NbEdges() );
1188   Standard_Integer n1 = ( n2  >1 ? n2-1 : sbwd->NbEdges() );
1189   TopoDS_Edge E1 = sbwd->Edge(n1);
1190   TopoDS_Edge E2 = sbwd->Edge(n2);
1191   
1192   ShapeAnalysis_Edge sae;
1193   TopoDS_Vertex V1 = sae.LastVertex (E1);
1194   TopoDS_Vertex V2 = sae.FirstVertex (E2);
1195   TopoDS_Vertex V;
1196   
1197   if ( myAnalyzer->LastCheckStatus ( ShapeExtend_DONE1 ) ) { // absolutely confused
1198     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
1199     //#40 rln 18.11.98 S4054 BUC60035 entity 2393 (2-nd sub-curve is edge with the same vertex)
1200     if ( V2.IsSame ( sae.LastVertex (E2) ) ) {
1201       V = V2;
1202       if ( ! Context().IsNull() ) 
1203         Context()->Replace ( V1, V.Oriented(V1.Orientation()) );
1204     }
1205     else {
1206       V = V1;
1207       if ( ! Context().IsNull() ) 
1208         Context()->Replace ( V2, V.Oriented(V2.Orientation()) );
1209     }
1210   } 
1211   else {    // on moyenne ...
1212     if ( myAnalyzer->LastCheckStatus ( ShapeExtend_DONE2 ) )
1213       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
1214     else myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
1215     ShapeBuild_Vertex sbv; 
1216     V = sbv.CombineVertex ( V1, V2, 1.0001 );
1217     if ( ! Context().IsNull() ) {
1218       Context()->Replace ( V1, V.Oriented(V1.Orientation()) );
1219       Context()->Replace ( V2, V.Oriented(V2.Orientation()) );
1220     }
1221   }
1222
1223   // replace vertices to a new one
1224   ShapeBuild_Edge sbe;
1225   if ( sbwd->NbEdges() <2 ) {
1226     if(E2.Free() && myTopoMode) {
1227       BRep_Builder B;
1228       B.Remove(E2,sae.FirstVertex(E2));
1229       B.Remove(E2,sae.LastVertex(E2));
1230       B.Add(E2,V.Oriented(TopAbs_FORWARD));
1231       B.Add(E2,V.Oriented(TopAbs_REVERSED));
1232     }
1233     else {
1234       TopoDS_Edge tmpE = sbe.CopyReplaceVertices ( E2, V, V );
1235       sbwd->Set ( tmpE, n2 );
1236       if ( ! Context().IsNull() ) Context()->Replace(E2,tmpE);
1237     }
1238   }
1239   else {
1240     if(E2.Free() &&E1.Free() && myTopoMode) {
1241       BRep_Builder B;
1242       B.Remove(E2,sae.FirstVertex(E2));
1243       B.Add(E2,V.Oriented(TopAbs_FORWARD));
1244       if ( ! myAnalyzer->LastCheckStatus ( ShapeExtend_DONE1 ) ||
1245           sae.FirstVertex (E2).IsSame (sae.LastVertex (E2)) ) {
1246         B.Remove(E1,sae.LastVertex(E1));
1247         B.Add(E1,V.Oriented(TopAbs_REVERSED));
1248       }
1249     }
1250     else {
1251       TopoDS_Edge tmpE2 = sbe.CopyReplaceVertices ( E2, V, TopoDS_Vertex() );
1252       sbwd->Set ( tmpE2, n2 );
1253       if ( ! Context().IsNull() ) Context()->Replace(E2,tmpE2);
1254       if ( ! myAnalyzer->LastCheckStatus ( ShapeExtend_DONE1 ) ||
1255           sae.FirstVertex (E2).IsSame (sae.LastVertex (E2)) ) {
1256         TopoDS_Edge tmpE1 = sbe.CopyReplaceVertices ( E1, TopoDS_Vertex(), V );
1257         sbwd->Set (tmpE1, n1 );
1258         if ( ! Context().IsNull() ) Context()->Replace(E1,tmpE1);
1259       }
1260     }
1261   }
1262   if ( ! Context().IsNull() ) UpdateWire();
1263   
1264   return Standard_True;
1265 }
1266
1267
1268 //=======================================================================
1269 //function : FixSeam
1270 //purpose  : 
1271 //=======================================================================
1272
1273 Standard_Boolean ShapeFix_Wire::FixSeam (const Standard_Integer num) 
1274 {
1275   myLastFixStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
1276   if ( ! IsReady() ) return Standard_False;
1277
1278   Handle(Geom2d_Curve) C1, C2;
1279   Standard_Real cf, cl;
1280   if ( ! myAnalyzer->CheckSeam (num, C1, C2, cf, cl) ) return Standard_False;
1281
1282   BRep_Builder B;
1283   TopoDS_Edge E = WireData()->Edge ( num >0 ? num : NbEdges() );
1284   B.UpdateEdge (E, C2,C1, Face(), 0.); //:S4136: BRep_Tool::Tolerance(E)
1285   B.Range (E, Face(),cf,cl);
1286   myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
1287   
1288   return Standard_True;
1289 }
1290
1291 //=======================================================================
1292 //function : FixShifted
1293 //purpose  : fix parametric curves which may be shifted
1294 // to whole parametric range of closed surface as result of recomputing
1295 // from 3d representation.
1296 // This can be a curve on a seam or near it.
1297 // This function is to be called before FixDegenerated.
1298 // LIMITATION: this function cannot fix cases when, e.g., closed wire is 
1299 // composed of two meridians of the sphere and one of them is seam.
1300 // NOTE: wire is supposed to be closed and sorted !
1301 //=======================================================================
1302
1303 //:p4 abv 23.02.99: PRO9234 #15720: update UV points of edge 
1304 static void UpdateEdgeUVPoints (TopoDS_Edge &E, const TopoDS_Face &F)
1305 {
1306   Standard_Real first, last;
1307   BRep_Tool::Range ( E, F, first, last );
1308   BRep_Builder().Range ( E, F, first, last );
1309 }
1310
1311
1312 //=======================================================================
1313 //function : FixShifted
1314 //purpose  : 
1315 //=======================================================================
1316
1317 Standard_Boolean ShapeFix_Wire::FixShifted() 
1318 {
1319   myLastFixStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
1320   if ( ! IsReady() ) return Standard_False;
1321
1322   Handle(ShapeAnalysis_Surface) surf = myAnalyzer->Surface();
1323   //#78 rln 12.03.99 S4135: checking spatial closure with Precision
1324   Standard_Boolean uclosed = surf->IsUClosed(Precision());
1325   Standard_Boolean vclosed = surf->IsVClosed(Precision()) || surf->Surface()->IsKind (STANDARD_TYPE(Geom_SphericalSurface));
1326   //#67 rln 01.03.99 S4135: ims010.igs entity D11900 (2D contour is 2*PI higher than V range [-pi/2,p/2])
1327   
1328   // PTV 26.06.2002 begin
1329   // CTS18546-2.igs entity 2222: base curve is periodic and 2dcurve is shifted
1330   Standard_Boolean IsVCrvClosed = Standard_False;
1331   Standard_Real VRange = 1.;
1332   if (surf->Surface()->IsKind (STANDARD_TYPE(Geom_SurfaceOfRevolution))) {
1333     Handle(Geom_SurfaceOfRevolution) aSurOfRev = Handle(Geom_SurfaceOfRevolution)::DownCast(surf->Surface());
1334     Handle(Geom_Curve) aBaseCrv = aSurOfRev->BasisCurve();
1335     while ( (aBaseCrv->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) ||
1336            (aBaseCrv->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) ) {
1337       if (aBaseCrv->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
1338         aBaseCrv = Handle(Geom_OffsetCurve)::DownCast(aBaseCrv)->BasisCurve();
1339       if (aBaseCrv->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
1340         aBaseCrv = Handle(Geom_TrimmedCurve)::DownCast(aBaseCrv)->BasisCurve();
1341     }
1342     if (aBaseCrv->IsPeriodic()) {
1343       vclosed = Standard_True;
1344       VRange = aBaseCrv->Period();
1345       IsVCrvClosed = Standard_True;
1346 #ifdef OCCT_DEBUG
1347       cout << "Warning: ShapeFix_Wire::FixShifted set vclosed True for Surface of Revolution" << endl;
1348 #endif
1349     }
1350   }
1351   // PTV 26.06.2002 end
1352   if ( ! uclosed && ! vclosed ) return Standard_False; 
1353   
1354   Standard_Real URange, /*VRange,*/ SUF, SUL, SVF, SVL;
1355   surf->Surface()->Bounds ( SUF, SUL, SVF, SVL );
1356   Standard_Real SUMid, SVMid;
1357   SUMid = 0.5*(SUF+SUL);
1358   SVMid = 0.5*(SVF+SVL);
1359   if (uclosed) URange = Abs ( SUL - SUF );
1360   else         URange = RealLast();
1361   if (!IsVCrvClosed) {
1362     if (vclosed) VRange = Abs ( SVL - SVF );
1363     else         VRange = RealLast();
1364   }
1365   Standard_Real UTol = 0.2 * URange, VTol = 0.2 * VRange;
1366
1367   Handle(ShapeExtend_WireData) sbwdOring = WireData();
1368   ShapeAnalysis_Edge sae;
1369   Handle(ShapeExtend_WireData) sbwd = new ShapeExtend_WireData;
1370   for ( Standard_Integer i=1; i <= sbwdOring->NbEdges(); i++ ) {
1371     TopoDS_Edge E1 = sbwdOring->Edge ( i );
1372     if ( BRep_Tool::Degenerated(E1) && !sae.HasPCurve(E1,Face()))
1373       continue;
1374     
1375     sbwd->Add(E1);
1376   }
1377   
1378   ShapeBuild_Edge sbe;
1379   Standard_Integer nb = sbwd->NbEdges();
1380   Standard_Boolean end = (nb == 0), degstop = Standard_False;;
1381   Standard_Integer stop = nb;
1382   Standard_Integer degn2 = 0;
1383   gp_Pnt pdeg;
1384   //pdn 17.12.98 r0901_ec 38237 to shift wire at 0
1385  
1386   //GeomAdaptor_Surface& GAS = myAnalyzer->Surface()->Adaptor3d()->ChangeSurface(); //SK
1387   Bnd_Box2d box;
1388   for ( Standard_Integer n2=1, n1=nb; ! end; n1 = n2++ ) {
1389     if ( n2 > nb ) n2 = 1;
1390     if ( n2 == stop ) end = Standard_True;
1391
1392     TopoDS_Edge E1 = sbwd->Edge ( n1 );
1393     TopoDS_Edge E2 = sbwd->Edge ( n2 );
1394
1395     if ( BRep_Tool::Degenerated(E1) || BRep_Tool::Degenerated(E2) )
1396     {
1397       if ( ! degstop )
1398       {
1399         stop = n2;
1400         degstop = Standard_True;
1401       }
1402       continue;
1403     }
1404
1405     TopoDS_Vertex V = sae.FirstVertex ( E2 );
1406     if (V.IsNull())
1407       continue;
1408
1409     gp_Pnt p = BRep_Tool::Pnt ( V );
1410   
1411     Standard_Real a1 = 0., b1 = 0., a2 = 0., b2 = 0.;
1412     Handle(Geom2d_Curve) c2d1, c2d2;
1413
1414     //:abv 29.08.01: torCuts.sat: distinguish degeneration by U and by V;
1415     // only corresponding move is prohibited
1416 //    Standard_Boolean isDeg = surf->IsDegenerated ( p, Max ( Precision(), BRep_Tool::Tolerance(V) ) );
1417     Standard_Integer isDeg = 0;
1418     gp_Pnt2d degP1, degP2;
1419     Standard_Real degT1, degT2;
1420     if ( surf->DegeneratedValues ( p, Max ( Precision(), BRep_Tool::Tolerance(V) ),
1421                                    degP1, degP2, degT1, degT2 ) )
1422       isDeg = ( Abs ( degP1.X() - degP2.X() ) > Abs ( degP1.Y() - degP2.Y() ) ? 1 : 2 );
1423
1424     // abv 23 Feb 00: UKI60107-6 210: additional check for near-degenerated case
1425     //smh#15 PRO19800. Check if the surface is surface of revolution.
1426     if (surf->Surface()->IsKind (STANDARD_TYPE(Geom_SurfaceOfRevolution))) {
1427       if ( ! isDeg && ! vclosed ) {
1428         if ( c2d1.IsNull() && ! sae.PCurve ( E1, Face(), c2d1, a1, b1, Standard_True ) ) continue;
1429         gp_Pnt2d p1 ( SUF, c2d1->Value(b1).Y() );
1430         gp_Pnt2d p2 ( SUL, c2d1->Value(b1).Y() );
1431         if ( surf->IsDegenerated ( p1, p2, MaxTolerance(), 10 ) &&
1432              ! surf->IsDegenerated ( c2d1->Value(a1), c2d1->Value(b1), MaxTolerance(), 10 ) ) // abv 31.07.00: trj4_pm1-ec-214.stp #31274: still allow work if edge already exists 
1433           isDeg = 1;
1434       }
1435       if ( ! isDeg && ! uclosed ) {
1436         if ( c2d1.IsNull() && ! sae.PCurve ( E1, Face(), c2d1, a1, b1, Standard_True ) ) continue;
1437         gp_Pnt2d p1 ( c2d1->Value(b1).X(), SVF );
1438         gp_Pnt2d p2 ( c2d1->Value(b1).X(), SVL );
1439         if ( surf->IsDegenerated ( p1, p2, MaxTolerance(), 10 ) &&
1440              ! surf->IsDegenerated ( c2d1->Value(a1), c2d1->Value(b1), MaxTolerance(), 10 ) ) // abv 31.07.00: trj4_pm1-ec-214.stp #31274: still allow work if edge already exists 
1441           isDeg = 2;
1442       }
1443     }
1444
1445     if ( isDeg )
1446     {
1447       if ( ! degstop )
1448       {
1449         stop = n2;
1450         degstop = Standard_True;
1451       }
1452
1453       if ( ! degn2 )
1454       {
1455         degn2 = n2;
1456         pdeg = p;
1457       }
1458       else
1459       {
1460         if ( pdeg.SquareDistance(p) < Precision() * Precision() )
1461         {
1462           degn2 = n2;
1463           //if ( stop < n2 ) { stop = n2; degstop = Standard_True; }
1464         }
1465         else
1466         {
1467           Standard_Real ax1 = 0., bx1 = 0., ax2 = 0., bx2 = 0.;
1468           Handle(Geom2d_Curve) cx1, cx2;
1469           if (  ( c2d1.IsNull() && ! sae.PCurve ( E1, Face(), c2d1, a1, b1, Standard_True ) ) ||
1470                 ( c2d2.IsNull() && ! sae.PCurve ( E2, Face(), c2d2, a2, b2, Standard_True ) ) ||
1471                 ! sae.PCurve ( sbwd->Edge ( degn2 >1 ? degn2-1 : nb ), Face(), cx1, ax1, bx1, Standard_True ) ||
1472                 ! sae.PCurve ( sbwd->Edge ( degn2 ), Face(), cx2, ax2, bx2, Standard_True ) )
1473           {
1474             myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
1475             continue;
1476           }
1477           gp_Pnt2d pd1 = cx1->Value ( bx1 );
1478           gp_Pnt2d pd2 = cx2->Value ( ax2 );
1479           gp_Pnt2d pn1 = c2d1->Value ( b1 );
1480           gp_Pnt2d pn2 = c2d2->Value ( a2 );
1481           gp_Vec2d x(0.,0.); // shift vector
1482           Standard_Real period;
1483           if ( uclosed ) { x.SetX ( 1. ); period = URange; }
1484           else { x.SetY ( 1. ); period = VRange; }
1485           Standard_Real rot1 = ( pn1.XY() - pd2.XY() ) ^ x.XY();
1486           Standard_Real rot2 = ( pd1.XY() - pn2.XY() ) ^ x.XY();
1487           Standard_Real scld = ( pd2.XY() - pd1.XY() ) * x.XY();
1488           Standard_Real scln = ( pn2.XY() - pn1.XY() ) * x.XY();
1489           if (  rot1 * rot2 < -::Precision::PConfusion() && 
1490                 scld * scln < -::Precision::PConfusion() && 
1491                 Abs ( scln ) > 0.1 * period && Abs ( scld ) > 0.1 * period && 
1492                 rot1 * scld > ::Precision::PConfusion() && 
1493                 rot2 * scln > ::Precision::PConfusion() )
1494           {
1495             // abv 02 Mar 00: trying more sophisticated analysis (ie_exhaust-A.stp #37520)
1496             Standard_Real sign = ( rot2 >0 ? 1. : -1. );
1497             Standard_Real deep1 = Min ( sign * ( pn2.XY() * x.XY() ),
1498                                   Min ( sign * ( pd1.XY() * x.XY() ),
1499                                   Min ( sign * ( c2d2->Value(b2 ).XY() * x.XY() ),
1500                                   Min ( sign * (  cx1->Value(ax1).XY() * x.XY() ),
1501                                   Min ( sign * ( c2d2->Value(0.5*(a2 +b2 )).XY() * x.XY() ),
1502                                         sign * (  cx1->Value(0.5*(ax1+bx1)).XY() * x.XY() ) ) ) ) ) );
1503             Standard_Real deep2 = Max ( sign * ( pn1.XY() * x.XY() ),
1504                                   Max ( sign * ( pd2.XY() * x.XY() ),
1505                                   Max ( sign * ( c2d1->Value(a1 ).XY() * x.XY() ),
1506                                   Max ( sign * (  cx2->Value(bx2).XY() * x.XY() ),
1507                                   Max ( sign * ( c2d1->Value(0.5*(a1 +b1 )).XY() * x.XY() ),
1508                                         sign * (  cx2->Value(0.5*(ax2+bx2)).XY() * x.XY() ) ) ) ) ) );
1509             Standard_Real deep = deep2 - deep1; // estimated current size of wire by x
1510             // pdn 30 Oct 00: trying correct period [0,period] (trj5_k1-tc-203.stp #4698)
1511             Standard_Real dx = ShapeAnalysis::AdjustToPeriod ( deep, ::Precision::PConfusion(), period+::Precision::PConfusion()); 
1512             x *= ( scld >0 ? -dx : dx );
1513             //x *= ( Abs(scld-scln) > 1.5 * period ? 2. : 1. ) *
1514             //     ( scld >0 ? -period : period );
1515             gp_Trsf2d Shift;
1516             Shift.SetTranslation ( x );
1517             for ( Standard_Integer k=degn2; ; k++ )
1518             {
1519               if ( k > nb ) k = 1;
1520               if ( k == n2 ) break;
1521               TopoDS_Edge edge = sbwd->Edge ( k );
1522               if ( ! sae.PCurve ( edge, Face(), cx1, ax1, bx1, Standard_True ) ) continue;
1523               //cx1->Transform ( Shift );
1524               // skl 15.05.2002 for OCC208 (if few edges have reference to one pcurve)
1525               Handle(Geom2d_Curve) cx1new = Handle(Geom2d_Curve)::DownCast(cx1->Transformed(Shift));
1526               sbe.ReplacePCurve(edge,cx1new,Face());
1527               UpdateEdgeUVPoints ( edge, Face() );
1528             }
1529             myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
1530 #ifdef OCCT_DEBUG
1531             cout << "Info: ShapeFix_Wire::FixShifted(): bi - meridian case fixed" << endl;
1532 #endif
1533             continue;
1534           }
1535           //degn2 = n2; pdeg = p; // ie_exhaust-A.stp #37520
1536         }
1537       }
1538 /*
1539       // pdn to fix half sphere
1540       TopoDS_Vertex VE = sae.LastVertex ( E2 );
1541       gp_Pnt pe = BRep_Tool::Pnt ( VE );
1542       //pdn is second vertex on singular point ?
1543       if ( surf->IsDegenerated ( pe, Max ( Precision(), BRep_Tool::Tolerance(V) ) ) ) {
1544         if ( ( c2d1.IsNull() && ! sae.PCurve ( E1, Face(), c2d1, a1, b1, Standard_True ) ) ||
1545              ( c2d2.IsNull() && ! sae.PCurve ( E2, Face(), c2d2, a2, b2, Standard_True ) ) ) {
1546           myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
1547           continue;
1548         }
1549         gp_Pnt2d p2d1 = c2d1->Value ( b1 ), p2f = c2d2->Value ( a2 ), p2l = c2d2->Value ( b2 );
1550         Standard_Real pres2 = ::Precision::PConfusion();
1551         Standard_Real du = 0.,dv = 0.;
1552         //#79 rln 15.03.99 S4135: bmarkmdl.igs entity 633 (incorrectly oriented contour) check for gap
1553         if(uclosed&&(Abs(p2f.X()-p2l.X())<pres2)&&Abs(p2d1.X()-p2f.X())>GAS.UResolution(Precision())) {
1554           if((Abs(p2f.X()-SUF)<pres2)&&(p2f.Y()<p2l.Y()))
1555             du = URange;
1556           if((Abs(p2f.X()-SUL)<pres2)&&(p2f.Y()>p2l.Y()))
1557             du = -URange;
1558         } 
1559         if(vclosed&&(Abs(p2f.Y()-p2l.Y())<pres2)&&Abs(p2d1.Y()-p2f.Y())>GAS.VResolution(Precision())) {
1560           if((Abs(p2f.Y()-SVF)<pres2)&&(p2f.X()>p2l.X()))
1561             dv = VRange;
1562           if((Abs(p2f.Y()-SVL)<pres2)&&(p2f.X()<p2l.X()))
1563             dv = -VRange;
1564         } 
1565         if ( du ==0. && dv == 0. ) continue;
1566         myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
1567         gp_Trsf2d Shift;
1568         Shift.SetTranslation ( gp_Vec2d ( du, dv ) );
1569         c2d2->Transform ( Shift );
1570         UpdateEdgeUVPoints ( E2, Face() );//rln 15.03.99 syntax correction :E1
1571       }
1572 */
1573 //:abv 29.08.01: torCuts.sat:      continue;
1574     }
1575
1576     if ( ( c2d1.IsNull() && ! sae.PCurve ( E1, Face(), c2d1, a1, b1, Standard_True ) ) ||
1577          ( c2d2.IsNull() && ! sae.PCurve ( E2, Face(), c2d2, a2, b2, Standard_True ) ) ) {
1578       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
1579       continue;
1580     }
1581     gp_Pnt2d p2d1 = c2d1->Value ( b1 );
1582     gp_Pnt2d p2d2 = c2d2->Value ( a2 );
1583     box.Add ( p2d1 );
1584
1585     Standard_Real du=0., dv=0.;
1586     if ( uclosed && isDeg != 1 ) {
1587       Standard_Real dx = Abs ( p2d2.X() - p2d1.X() );
1588       if ( dx > URange - UTol ) 
1589         du = ShapeAnalysis::AdjustByPeriod ( p2d2.X(), p2d1.X(), URange );
1590       else if ( dx > UTol && stop == nb ) stop = n2; //:abv 29.08.01: torCuts2.stp
1591     }
1592     if ( vclosed && isDeg != 2 ) {
1593       Standard_Real dy = Abs ( p2d2.Y() - p2d1.Y() );
1594       if ( dy > VRange - VTol ) 
1595         dv = ShapeAnalysis::AdjustByPeriod ( p2d2.Y(), p2d1.Y(), VRange );
1596       else if ( dy > VTol && stop == nb ) stop = n2;
1597     }
1598     if ( du ==0. && dv == 0. ) continue;
1599
1600     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
1601     gp_Trsf2d Shift;
1602     Shift.SetTranslation ( gp_Vec2d ( du, dv ) );
1603     //c2d2->Transform ( Shift );
1604     // skl 15.05.2002 for OCC208 (if few edges have reference to one pcurve)
1605     Handle(Geom2d_Curve) c2d2new = Handle(Geom2d_Curve)::DownCast(c2d2->Transformed(Shift));
1606     sbe.ReplacePCurve(E2,c2d2new,Face());
1607     UpdateEdgeUVPoints ( E2, Face() );
1608   }
1609   if ( box.IsVoid() ) return Standard_False; //#3 smh 01.04.99. S4163: Overflow, when box is void.
1610
1611   Standard_Real umin, vmin, umax, vmax;
1612   box.Get ( umin, vmin, umax, vmax );
1613   if ( Abs ( umin + umax - SUF - SUL ) < URange &&
1614        Abs ( vmin + vmax - SVF - SVL ) < VRange &&
1615        ! LastFixStatus ( ShapeExtend_DONE ) ) return Standard_False;
1616
1617   box.SetVoid();
1618   Standard_Integer n; // svv Jan11 2000 : porting on DEC
1619   for ( n=1; n <= nb; n++ ) {
1620     Standard_Real a, b;
1621     Handle(Geom2d_Curve) c2d;
1622     if ( ! sae.PCurve ( sbwd->Edge(n), Face(), c2d, a, b, Standard_True ) ) continue;
1623     box.Add ( c2d->Value ( a ) );
1624     box.Add ( c2d->Value ( 0.5 * ( a + b ) ) );
1625   }
1626   box.Get ( umin, vmin, umax, vmax );
1627
1628   Standard_Real du=0., dv=0.;
1629
1630   if ( uclosed ) {
1631     Standard_Real umid = 0.5 * ( umin + umax );
1632 //     du = ShapeAnalysis::AdjustToPeriod(umid, SUF, SUL);
1633     // PTV 26.06.2002 xloop torus-apple iges face mode
1634     du = ShapeAnalysis::AdjustByPeriod(umid, SUMid, URange);
1635   }
1636   if ( vclosed ) {
1637     Standard_Real vmid = 0.5 * ( vmin + vmax );
1638 //     dv = ShapeAnalysis::AdjustToPeriod(vmid, SVF, SVL);
1639     // PTV 26.06.2002 xloop torus-apple iges face mode
1640     dv = ShapeAnalysis::AdjustByPeriod(vmid, SVMid, VRange);
1641   }
1642
1643   if ( du ==0. && dv == 0. ) return Standard_True;
1644
1645   myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
1646   
1647   gp_Trsf2d Shift;
1648   Shift.SetTranslation ( gp_Vec2d ( du, dv ) );
1649
1650   for ( n=1; n <= sbwdOring->NbEdges(); n++ ) {
1651     Standard_Real a, b;
1652     Handle(Geom2d_Curve) c2d;
1653     TopoDS_Edge ed = sbwdOring->Edge(n);
1654     if ( ! sae.PCurve ( ed, Face(), c2d, a, b, Standard_True ) ) continue;
1655     // skl 15.05.2002 for OCC208 (if few edges have reference to one pcurve)
1656     Handle(Geom2d_Curve) c2d2 = Handle(Geom2d_Curve)::DownCast(c2d->Transformed(Shift));
1657     sbe.ReplacePCurve(ed,c2d2,Face());
1658     UpdateEdgeUVPoints ( ed, Face() );
1659   }
1660   return Standard_True;
1661 }
1662
1663 //=======================================================================
1664 //function : FixDegenerated
1665 //purpose  : 
1666 //=======================================================================
1667
1668 Standard_Boolean ShapeFix_Wire::FixDegenerated (const Standard_Integer num) 
1669 {
1670   myLastFixStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
1671   if ( ! IsReady() ) return Standard_False;
1672
1673   // analysis
1674   gp_Pnt2d p2d1, p2d2;
1675   myAnalyzer->CheckDegenerated ( num, p2d1, p2d2 );
1676   if ( myAnalyzer->LastCheckStatus ( ShapeExtend_FAIL1 ) ) {
1677     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
1678   }
1679   //: abv 29.08.01: torHalf2.sat: if edge was encoded as degenerated but 
1680   //  has no pcurve and no singularity is found at that point, remove it
1681   if ( myAnalyzer->LastCheckStatus ( ShapeExtend_FAIL2 ) ) {
1682     WireData()->Remove ( num );
1683     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
1684     return Standard_True;
1685   }
1686   if ( ! myAnalyzer->LastCheckStatus ( ShapeExtend_DONE ) ) return Standard_False;
1687   
1688   // action: create degenerated edge and insert it (or replace)
1689
1690   gp_Vec2d vect2d ( p2d1, p2d2 );
1691   gp_Dir2d dir2d ( vect2d );
1692   Handle(Geom2d_Line) line2d = new Geom2d_Line ( p2d1, dir2d );
1693
1694   TopoDS_Edge degEdge;
1695   BRep_Builder B;
1696   B.MakeEdge ( degEdge );
1697   B.Degenerated ( degEdge, Standard_True );
1698   B.UpdateEdge ( degEdge, line2d, Face(), ::Precision::Confusion() );
1699   B.Range ( degEdge, Face(), 0., vect2d.Magnitude() );
1700
1701   Handle(ShapeExtend_WireData) sbwd = WireData();
1702   Standard_Integer n2 = ( num >0 ? num  : sbwd->NbEdges() );
1703   Standard_Integer n1 = ( n2  >1 ? n2-1 : sbwd->NbEdges() );
1704   
1705   Standard_Boolean lack = myAnalyzer->LastCheckStatus ( ShapeExtend_DONE1 );
1706   Standard_Integer n3 = ( lack ? n2 : ( n2 < sbwd->NbEdges() ? n2+1 : 1 ) );
1707   
1708   ShapeAnalysis_Edge sae;
1709   TopoDS_Vertex V1 = sae.LastVertex ( sbwd->Edge ( n1 ) );
1710   TopoDS_Vertex V2 = sae.FirstVertex ( sbwd->Edge ( n3 ) );
1711   
1712   V1.Orientation(TopAbs_FORWARD);
1713   V2.Orientation(TopAbs_REVERSED);
1714   B.Add(degEdge,V1);
1715   B.Add(degEdge,V2);
1716   degEdge.Orientation(TopAbs_FORWARD);
1717
1718   if ( lack ) {
1719     sbwd->Add ( degEdge, n2 );
1720     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
1721   }
1722   else {
1723     sbwd->Set ( degEdge, n2 );
1724     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
1725   }
1726
1727 //  commented to avoid extra messages
1728 //  SendWarning ( degEdge, Message_Msg ( "FixWire.FixDegenerated.MSG0" ) );// Degenerated edge(s) detected
1729
1730   return Standard_True;
1731 }
1732
1733 //=======================================================================
1734 //function : FixSelfIntersectingEdge
1735 //purpose  : Tests edge for self-intersection and updates tolerance of vertex
1736 //           if intersection is found
1737 //           Returns True if tolerance was increased
1738 //=======================================================================
1739
1740 // Create edge on basis of E with new pcurve and call FixSP
1741 // Return resulting tolerance and modified pcurve
1742 static Standard_Boolean TryNewPCurve (const TopoDS_Edge &E, const TopoDS_Face &face,
1743                                       Handle(Geom2d_Curve) &c2d,
1744                                       Standard_Real &first,
1745                                       Standard_Real &last,
1746                                       Standard_Real &tol)
1747 {
1748   Standard_Real f, l;
1749   Handle(Geom_Curve) crv = BRep_Tool::Curve ( E, f, l );
1750   if ( crv.IsNull() ) return Standard_False;
1751
1752   // make temp edge and compute tolerance
1753   BRepBuilderAPI_MakeEdge mkedge ( crv, f, l );
1754
1755   ShapeBuild_Edge SBE;        //skl 17.07.2001
1756   SBE.SetRange3d(mkedge,f,l); //skl 17.07.2001
1757
1758   if ( ! mkedge.IsDone() ) return Standard_False;
1759
1760   TopoDS_Edge edge = mkedge;
1761   BRep_Builder B;
1762   B.UpdateEdge ( edge, c2d, face, 0. );
1763   B.Range ( edge, face, first, last );
1764   B.SameRange ( edge, Standard_False );
1765 // no call to BRepLib:  B.SameParameter ( edge, Standard_False );
1766
1767   Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
1768   sfe->FixSameParameter ( edge ); 
1769   c2d = BRep_Tool::CurveOnSurface ( edge, face, first, last );
1770   tol = BRep_Tool::Tolerance ( edge );
1771   return Standard_True;
1772 }
1773   
1774 //:k3 abv 24 Dec 98: BUC50070 #26682 and #30087: 
1775 // Try to cut out the loop on the pcurve and make new pcurve by concatenating
1776 // the parts.
1777 // If result is not SameParameter with prec, does nothing and returns False
1778 // Warning: resulting pcurve will be C0
1779
1780 //=======================================================================
1781 //function : howMuchPCurves
1782 //purpose  : OCC901
1783 //=======================================================================
1784 static Standard_Integer howMuchPCurves (const TopoDS_Edge &E)
1785 {
1786   Standard_Integer count = 0;
1787   BRep_ListIteratorOfListOfCurveRepresentation itcr
1788     ((*((Handle(BRep_TEdge)*)&E.TShape()))->ChangeCurves());
1789
1790   while (itcr.More()) {
1791     const Handle(BRep_CurveRepresentation)& cr = itcr.Value();
1792     if ( cr->IsCurveOnSurface() )
1793       count++;
1794     itcr.Next();
1795   }
1796     
1797   return count;
1798 }
1799
1800
1801 //=======================================================================
1802 //function : RemoveLoop
1803 //purpose  : 
1804 //=======================================================================
1805 static Standard_Boolean RemoveLoop (TopoDS_Edge &E, const TopoDS_Face &face,
1806                                     const IntRes2d_IntersectionPoint &IP,
1807                                     const Standard_Real tolfact,
1808                                     const Standard_Real prec,
1809                                     const Standard_Boolean RemoveLoop3d)
1810 {
1811   Standard_Boolean loopRemoved3d;
1812   if ( BRep_Tool::IsClosed ( E, face ) ) return Standard_False;
1813   
1814   Standard_Real f, l;
1815   Handle(Geom_Curve) crv = BRep_Tool::Curve ( E, f, l );
1816
1817   Standard_Real t1 = IP.ParamOnFirst();
1818   Standard_Real t2 = IP.ParamOnSecond();
1819   if ( t1 > t2 ) { Standard_Real t = t1; t1 = t2; t2 = t; }
1820
1821   ShapeAnalysis_Edge sae;
1822   Standard_Real a, b;
1823   Handle(Geom2d_Curve) c2d;
1824   if ( ! sae.PCurve ( E, face, c2d, a, b, Standard_False ) ) 
1825     return Standard_False;
1826
1827 #ifdef OCCT_DEBUG
1828   cout << "Cut Loop: params (" << t1 << ", " << t2;
1829 #endif
1830   GeomAdaptor_Curve GAC ( crv, f, l );
1831   Standard_Real dt = tolfact * GAC.Resolution(prec);
1832   t1 -= dt; //1e-3;//::Precision::PConfusion();
1833   t2 += dt; //1e-3;//::Precision::PConfusion();
1834 #ifdef OCCT_DEBUG
1835   cout << ") -> (" << t1 << ", " << t2 << ")" << endl;
1836 #endif
1837       
1838   if ( t1 <= a || t2 >= b ) { // should not be so, but to be sure ..
1839     return Standard_False;
1840   }
1841
1842   // direct construction causes error on osf system.
1843   gp_Pnt p(0,0,0);
1844   gp_Dir d(0,0,1);
1845   gp_Ax3 ax(p, d);
1846   gp_Pln Pln (ax);
1847   
1848   // PTV OCC884
1849   Handle(Geom_Plane) aPlaneSurf = Handle(Geom_Plane)::DownCast( BRep_Tool::Surface(face) );
1850   Handle(Geom_Curve) pcurve3d = crv;
1851   if ( !aPlaneSurf.IsNull() ) {
1852     Pln =  aPlaneSurf->Pln();
1853   }
1854   else
1855     pcurve3d = GeomAPI::To3d ( c2d, Pln );
1856
1857   // first segment
1858   //Handle(Geom_Curve) pcurve3d = GeomAPI::To3d ( c2d, Pln );
1859   Handle(Geom_TrimmedCurve) trim = new Geom_TrimmedCurve (pcurve3d, a, t1);
1860   GeomConvert_CompCurveToBSplineCurve connect ( trim );
1861   
1862   // null-length segment patch instead of loop
1863   TColgp_Array1OfPnt Poles(1,2);
1864   TColStd_Array1OfReal Knots(1,2);
1865   TColStd_Array1OfInteger Mults(1,2);
1866
1867   Poles.SetValue(1,trim->Value(t1));
1868   Knots.SetValue(1,t1);
1869   Mults.SetValue(1,2);
1870
1871   trim = new Geom_TrimmedCurve (pcurve3d, t2, b);
1872   Poles.SetValue(2,trim->Value(t2));
1873   Knots.SetValue(2,t2);
1874   Mults.SetValue(2,2);
1875
1876   Handle(Geom_BSplineCurve) patch = new Geom_BSplineCurve ( Poles, Knots, Mults, 1 );
1877   if ( ! connect.Add (patch, ::Precision::PConfusion(), Standard_True, Standard_False) )
1878     return Standard_False;
1879   
1880   // last segment
1881   if ( ! connect.Add (trim, ::Precision::PConfusion(), Standard_True, Standard_False) )
1882     return Standard_False;
1883   // PTV OCC884
1884   // keep created 3d curve
1885   Handle(Geom_Curve) aNew3dCrv = connect.BSplineCurve();
1886   
1887   
1888   Handle(Geom2d_Curve) bs = GeomAPI::To2d ( aNew3dCrv, Pln );
1889   if ( bs.IsNull() ) return Standard_False;
1890   
1891   // make temp edge and compute tolerance
1892   BRep_Builder B;
1893
1894   if(!RemoveLoop3d) { // old variant (not remove loop 3d)
1895     Standard_Real newtol=0;
1896     // OCC901
1897     Standard_Integer nbC2d = howMuchPCurves( E );
1898     if ( nbC2d <= 1  && !aPlaneSurf.IsNull() )
1899       B.UpdateEdge ( E, bs, face, 0 );
1900     else
1901       if ( ! TryNewPCurve ( E, face, bs, a, b, newtol ) ) return Standard_False;
1902   
1903     Standard_Real tol = BRep_Tool::Tolerance ( E );
1904 #ifdef OCCT_DEBUG
1905     cout << "Cut Loop: tol orig " << tol << ", prec " << prec << ", new tol " << newtol << endl;
1906 #endif
1907     if ( newtol > Max ( prec, tol ) ) return Standard_False;
1908     //:s2  bs = BRep_Tool::CurveOnSurface ( edge, face, a, b );
1909     if ( Abs ( a - f ) > ::Precision::PConfusion() || // smth strange, cancel
1910          Abs ( b - l ) > ::Precision::PConfusion() ) return Standard_False;
1911     // PTV OCC884
1912     if ( !aPlaneSurf.IsNull() ) {
1913       B.UpdateEdge ( E, aNew3dCrv, Max (newtol, tol) );
1914       // OCC901
1915       if ( ! TryNewPCurve ( E, face, bs, a, b, newtol ) ) return Standard_False;
1916     }
1917     B.UpdateEdge ( E, bs, face, newtol );
1918     B.UpdateVertex ( sae.FirstVertex ( E ), newtol );
1919     B.UpdateVertex ( sae.LastVertex  ( E ), newtol );
1920     return Standard_True;
1921   }
1922
1923   //:q1
1924   TopLoc_Location L;
1925   Handle(Geom_Surface) S = BRep_Tool::Surface(face, L);
1926   Handle(Geom2dAdaptor_HCurve) AC = new Geom2dAdaptor_HCurve(c2d);
1927   Handle(GeomAdaptor_HSurface) AS = new GeomAdaptor_HSurface(S);
1928   
1929   Adaptor3d_CurveOnSurface ACS(AC,AS);
1930   gp_Pnt P1(ACS.Value(t1));
1931   gp_Pnt P2(ACS.Value(t2));
1932   gp_Pnt pcurPnt((P1.X()+P2.X())/2,(P1.Y()+P2.Y())/2,(P1.Z()+P2.Z())/2);
1933   
1934   ShapeAnalysis_TransferParametersProj SFTP(E,face);
1935   Handle(TColStd_HSequenceOfReal) Seq2d = new TColStd_HSequenceOfReal;
1936   Seq2d->Append(t1);
1937   Seq2d->Append(t2);
1938   Seq2d->Append((t1+t2)/2);
1939   Handle(TColStd_HSequenceOfReal) Seq3d = SFTP.Perform(Seq2d,Standard_False);
1940   
1941   Standard_Real dist1 = pcurPnt.Distance(crv->Value(Seq3d->Value(1)));// correting Seq3d already project 
1942   Standard_Real dist2 = pcurPnt.Distance(crv->Value(Seq3d->Value(2)));
1943   Standard_Real dist3 = pcurPnt.Distance(crv->Value(Seq3d->Value(3)));
1944   Standard_Real ftrim,ltrim;
1945   if(dist3>Max(dist1,dist2)) {
1946     loopRemoved3d = Standard_False;
1947   }
1948   else {
1949     loopRemoved3d = Standard_True;
1950   }
1951   
1952   Handle(Geom_Curve) bs1;
1953   
1954   if (!loopRemoved3d) {
1955     // create new 3d curve
1956     ftrim = Seq3d->Value(1);
1957     ltrim = Seq3d->Value(2);
1958     ftrim-=dt;
1959     ltrim+=dt;
1960     Handle(Geom_TrimmedCurve) trim1 = new Geom_TrimmedCurve (crv, f, ftrim);
1961     GeomConvert_CompCurveToBSplineCurve connect1 ( trim1 );
1962     TColgp_Array1OfPnt      Poles1(1,2);
1963     TColStd_Array1OfReal    Knots1(1,2);
1964     TColStd_Array1OfInteger Mults1(1,2);
1965     
1966     Poles1.SetValue(1,trim1->Value(ftrim));
1967     Knots1.SetValue(1,ftrim);
1968     Mults1.SetValue(1,2);
1969     
1970     trim1 = new Geom_TrimmedCurve (crv, ltrim, l);
1971     Poles1.SetValue(2,trim1->Value(ltrim));
1972     Knots1.SetValue(2,ltrim);
1973     Mults1.SetValue(2,2);
1974   
1975     // create b-spline curve
1976     Handle(Geom_BSplineCurve) patch1 = new Geom_BSplineCurve ( Poles1, Knots1, Mults1, 1 );
1977   
1978     if ( ! connect1.Add (patch1, ::Precision::PConfusion(), Standard_True, Standard_False) )
1979       return Standard_False;
1980     
1981     // last segment
1982     if ( ! connect1.Add (trim1, ::Precision::PConfusion(), Standard_True, Standard_False) )
1983       return Standard_False;
1984     
1985     bs1 = connect1.BSplineCurve();
1986     
1987     if ( bs1.IsNull() )
1988       return Standard_False;
1989   }
1990 //  Standard_Real oldtol = BRep_Tool::Tolerance ( E );
1991
1992   if (!loopRemoved3d)
1993     B.UpdateEdge ( E, bs1, L, 0. );
1994   B.UpdateEdge ( E, bs, face, 0. );
1995   B.Range ( E, face, f, l );
1996   B.SameRange ( E, Standard_False );
1997
1998   Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
1999   sfe->FixSameParameter ( E ); 
2000
2001   return Standard_True;
2002 }
2003
2004 //=======================================================================
2005 //function : RemoveLoop
2006 //purpose  : 
2007 //=======================================================================
2008 static Standard_Boolean RemoveLoop (TopoDS_Edge &E, const TopoDS_Face &face,
2009                                     const IntRes2d_IntersectionPoint &IP2d,
2010                                     TopoDS_Edge &E1,
2011                                     TopoDS_Edge &E2)
2012 {
2013 #ifdef OCCT_DEBUG
2014   cout<<"Info: ShapeFix_Wire::FixSelfIntersection : Try insert vertex"<<endl;
2015 #endif
2016
2017   if ( BRep_Tool::IsClosed ( E, face ) ) return Standard_False;
2018   
2019   Standard_Real f, l;
2020   Handle(Geom_Curve) crv = BRep_Tool::Curve ( E, f, l );
2021
2022   Standard_Real t1 = IP2d.ParamOnFirst();
2023   Standard_Real t2 = IP2d.ParamOnSecond();
2024   
2025   if ( t1 > t2 ) 
2026   { 
2027     Standard_Real t = t1; t1 = t2; t2 = t; 
2028   }
2029
2030   ShapeAnalysis_Edge sae;
2031   
2032   // define vertexes Vfirst , Vlast, Vmid
2033   TopoDS_Vertex Vfirst,Vlast,Vmid;
2034   // initialize Vfirst and Vlast
2035   Vfirst = sae.FirstVertex(E);
2036   Vlast  = sae.LastVertex(E); 
2037   
2038   // find a 2d curve and parameters from edge E
2039   Standard_Real a, b;
2040   Handle (Geom2d_Curve) c2d;
2041   if ( ! sae.PCurve ( E, face, c2d, a, b, Standard_False ) ) 
2042     return Standard_False;
2043
2044   // first segment for 2d curve
2045   Handle(Geom2d_TrimmedCurve) trim1;
2046   if( (t1-a)>Precision::PConfusion() )
2047     trim1 = new Geom2d_TrimmedCurve (c2d, a, t1);
2048   // second segment for 2d curve
2049   Handle(Geom2d_TrimmedCurve) trim2 = new Geom2d_TrimmedCurve (c2d, t2, b);
2050
2051 //  if ( trim1.IsNull() || trim2.IsNull()  ) 
2052   if(trim2.IsNull()) 
2053     return Standard_False;
2054
2055   TopLoc_Location L;
2056   Handle (Geom_Surface) S = BRep_Tool::Surface(face, L);
2057   Handle (Geom2dAdaptor_HCurve) AC = new Geom2dAdaptor_HCurve(c2d);
2058   Handle (GeomAdaptor_HSurface) AS = new GeomAdaptor_HSurface(S); 
2059   
2060   Adaptor3d_CurveOnSurface ACS(AC,AS);
2061   gp_Pnt P1(ACS.Value(t1));
2062   gp_Pnt P2(ACS.Value(t2));
2063   gp_Pnt pcurPnt((P1.X()+P2.X())/2,(P1.Y()+P2.Y())/2,(P1.Z()+P2.Z())/2);
2064   
2065   // transfer parameters from pcurve to 3d curve
2066   ShapeAnalysis_TransferParametersProj SFTP(E,face);
2067   Handle (TColStd_HSequenceOfReal) Seq2d = new TColStd_HSequenceOfReal;
2068   Seq2d->Append(t1);
2069   Seq2d->Append(t2);
2070   Seq2d->Append((t1+t2)/2);
2071   Handle (TColStd_HSequenceOfReal) Seq3d = SFTP.Perform(Seq2d,Standard_False);
2072   
2073   Standard_Real dist1 = pcurPnt.Distance(crv->Value(Seq3d->Value(1)));// correting Seq3d already project 
2074   Standard_Real dist2 = pcurPnt.Distance(crv->Value(Seq3d->Value(2)));
2075   Standard_Real dist3 = pcurPnt.Distance(crv->Value(Seq3d->Value(3)));
2076   Standard_Real ftrim,ltrim;
2077   if ( dist3 > Max(dist1, dist2)) { // is loop in 3d
2078     ftrim = Seq3d->Value(1);
2079     ltrim = Seq3d->Value(2);
2080   }
2081   else { // not loop in 3d
2082     ftrim = Seq3d->Value(3);
2083     ltrim = Seq3d->Value(3);
2084   }
2085   
2086 //  ftrim = Seq3d->Value(1);
2087 //  ltrim = Seq3d->Value(2);
2088   
2089   // trim for 3d curve 'crv' with parameters from 'f' to 'l' 
2090   Handle(Geom_TrimmedCurve) trim3;
2091   if(!trim1.IsNull())
2092     trim3 = new Geom_TrimmedCurve (crv, f, ftrim);
2093   // second segment for 3d curve
2094   Handle(Geom_TrimmedCurve) trim4 = new Geom_TrimmedCurve (crv, ltrim, l);
2095
2096 //  if ( trim3.IsNull() || trim4.IsNull()  ) 
2097   if(trim4.IsNull()) 
2098     return Standard_False;
2099   
2100   // create a point for middle vertex
2101   gp_Pnt pnt1 = crv->Value(ftrim);
2102   gp_Pnt pnt2 = crv->Value(ltrim);
2103   gp_Pnt Pmid((pnt1.X()+pnt2.X())/2,(pnt1.Y()+pnt2.Y())/2,(pnt1.Z()+pnt2.Z())/2);
2104     
2105   BRep_Builder B;
2106   
2107   // create new copies for E1 and E2
2108   if(!trim1.IsNull())
2109     E1=TopoDS::Edge(E.EmptyCopied());
2110   E2=TopoDS::Edge(E.EmptyCopied());
2111   
2112   // initialize middle vertex Vmid
2113   if(trim1.IsNull()) 
2114     B.MakeVertex(Vmid, pnt2, 0.);
2115   else
2116     B.MakeVertex(Vmid, Pmid, 0.);
2117   
2118   ShapeBuild_Edge sbe;
2119   
2120   // replace verteces for new edges E1 and E2
2121   if (E.Orientation()== TopAbs_FORWARD)
2122   {
2123     if(!E1.IsNull())
2124       E1=sbe.CopyReplaceVertices(E1,Vfirst,Vmid);
2125     E2=sbe.CopyReplaceVertices(E2,Vmid, Vlast);
2126   }
2127   else 
2128   {
2129     if(!E1.IsNull())
2130       E1=sbe.CopyReplaceVertices(E1,Vmid, Vlast);
2131     E2=sbe.CopyReplaceVertices(E2,Vfirst, Vmid);
2132   }
2133   
2134   // Update edges by 2d and 3d curves
2135   Handle(ShapeFix_Edge) mySfe = new ShapeFix_Edge;
2136   if(!E1.IsNull()) {
2137     B.UpdateEdge(E1, trim1, face, 0.);
2138     B.UpdateEdge(E1, trim3, 0.);
2139     B.Range(E1, f, ftrim);
2140     B.SameRange(E1,Standard_False);
2141 //    B.SameParameter(E1,Standard_False);
2142     mySfe->FixSameParameter(E1);
2143     mySfe->FixVertexTolerance(E1);
2144   }
2145   B.UpdateEdge(E2, trim2, face, 0.);
2146   B.UpdateEdge(E2, trim4, 0.);
2147   B.Range ( E2,ltrim,l     );
2148   B.SameRange(E2, Standard_False );
2149 //  B.SameParameter(E2, Standard_False);
2150   mySfe->FixSameParameter(E2);
2151   mySfe->FixVertexTolerance(E2);
2152
2153   return Standard_True;
2154 }
2155
2156
2157 //=======================================================================
2158 //function : FixSelfIntersectingEdge
2159 //purpose  : 
2160 //=======================================================================
2161
2162 Standard_Boolean ShapeFix_Wire::FixSelfIntersectingEdge (const Standard_Integer num) 
2163 {
2164   myLastFixStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
2165   if ( ! IsReady() ) return Standard_False;
2166
2167   // analysis
2168   IntRes2d_SequenceOfIntersectionPoint points2d;
2169   TColgp_SequenceOfPnt points3d;
2170   Handle(ShapeAnalysis_Wire) theAdvAnalyzer =  Handle(ShapeAnalysis_Wire)::DownCast(myAnalyzer);
2171   if (theAdvAnalyzer.IsNull()) return Standard_False;
2172   theAdvAnalyzer->CheckSelfIntersectingEdge ( num, points2d, points3d ); 
2173   if ( theAdvAnalyzer->LastCheckStatus ( ShapeExtend_FAIL ) ) {
2174     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
2175   }
2176   if ( ! theAdvAnalyzer->LastCheckStatus ( ShapeExtend_DONE ) ) return Standard_False;
2177   
2178   // action: increase tolerance of vertex
2179   
2180   TopoDS_Edge E = WireData()->Edge ( num >0 ? num : NbEdges() );
2181   
2182   ShapeAnalysis_Edge sae;
2183   TopoDS_Vertex V1 = sae.FirstVertex ( E );
2184   TopoDS_Vertex V2 = sae.LastVertex ( E );
2185   Standard_Real tol1 = BRep_Tool::Tolerance ( V1 );
2186   Standard_Real tol2 = BRep_Tool::Tolerance ( V2 );
2187   gp_Pnt pnt1 = BRep_Tool::Pnt ( V1 );
2188   gp_Pnt pnt2 = BRep_Tool::Pnt ( V2 );
2189
2190   // cycle is to verify fix in case of RemoveLoop
2191   Standard_Real tolfact = 0.1; // factor for shifting by parameter in RemoveLoop
2192   Standard_Real f2d = 0., l2d = 0.;
2193   Handle(Geom2d_Curve) c2d;
2194   Standard_Real newtol=0.; // = Precision();
2195
2196   if (myRemoveLoopMode<1) {
2197     for ( Standard_Integer iter=0; iter < 30; iter++ ) { 
2198       Standard_Boolean loopRemoved = Standard_False;;
2199       Standard_Real prevFirst = 0 , prevLast = 0; 
2200       for ( Standard_Integer i=1; i<=points2d.Length(); i++ ) {
2201         gp_Pnt pint = points3d.Value(i);
2202         Standard_Real dist21 = pnt1.SquareDistance ( pint );
2203         Standard_Real dist22 = pnt2.SquareDistance ( pint );
2204         if ( dist21 < tol1 * tol1 || dist22 < tol2 * tol2 ) continue;
2205         newtol = 1.001 * Sqrt ( Min ( dist21, dist22 ) ); //:f8
2206
2207         //:k3 abv 24 Dec 98: BUC50070 #26682 and #30087: try to remove loop
2208         if ( myGeomMode ) {
2209           if ( c2d.IsNull() )
2210             sae.PCurve ( E, Face(), c2d, f2d, l2d, Standard_False );
2211           Standard_Real firstpar = points2d.Value(i).ParamOnFirst(); 
2212           Standard_Real lastpar = points2d.Value(i).ParamOnSecond();
2213           if(firstpar > prevFirst && lastpar < prevLast) continue;
2214           if ( RemoveLoop (E, Face(), points2d.Value(i), tolfact, 
2215                            Min( MaxTolerance(), Max(newtol,Precision()) ),
2216                            myRemoveLoopMode==0 ) ) {
2217             myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
2218             loopRemoved = Standard_True;
2219             prevFirst = firstpar;
2220             prevLast = lastpar;
2221             continue; // repeat of fix on that edge required (to be done by caller)
2222           }
2223         }
2224         if ( newtol < MaxTolerance() ) {
2225           myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
2226           BRep_Builder B;
2227           if ( dist21 < dist22 ) B.UpdateVertex ( V1, tol1 = newtol );
2228           else                   B.UpdateVertex ( V2, tol2 = newtol );
2229         }
2230         else myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
2231       }
2232
2233       // after RemoveLoop, check that self-intersection disappeared
2234       if ( loopRemoved ) {
2235         IntRes2d_SequenceOfIntersectionPoint pnts2d;
2236         TColgp_SequenceOfPnt pnts3d;
2237         theAdvAnalyzer->CheckSelfIntersectingEdge ( num, pnts2d, pnts3d );
2238         if ( ! theAdvAnalyzer->LastCheckStatus ( ShapeExtend_DONE ) ) break;
2239         //points3d.Append(pnts3d);
2240         //points2d.Append(pnts2d);
2241         points3d = pnts3d;
2242         points2d = pnts2d;
2243         BRep_Builder B;
2244         B.UpdateEdge ( E, c2d, Face(), 0. );
2245         B.Range ( E, Face(), f2d, l2d );
2246         //newtol+=Precision();
2247       }
2248       else {
2249         break;
2250       }
2251     }
2252   }
2253   
2254   //===============================================
2255   // RemoveLoopMode = 1 , insert vertex 
2256   //===============================================
2257   if (myRemoveLoopMode == 1) {
2258     // after fixing will be nb+1 edges
2259     Standard_Boolean loopRemoved; 
2260     // create a sequence of resulting edges
2261     Handle (TopTools_HSequenceOfShape) TTSS = new TopTools_HSequenceOfShape;
2262     TopoDS_Edge E2;
2263     
2264     loopRemoved = Standard_False;
2265     //:k3 abv 24 Dec 98: BUC50070 #26682 and #30087: try to remove loop
2266     if ( myGeomMode ) {
2267       if ( c2d.IsNull() )
2268         sae.PCurve ( E, Face(), c2d, f2d, l2d, Standard_False );
2269       TopoDS_Edge E1;
2270       if ( RemoveLoop (E, Face(), points2d.Value(1),E1,E2) ) {
2271         myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
2272         loopRemoved = Standard_True;
2273         if(!E1.IsNull()) {
2274           TTSS->Append(E1);
2275           newtol = Max(BRep_Tool::Tolerance(E1),BRep_Tool::Tolerance(E2));
2276         }
2277         else
2278           newtol = BRep_Tool::Tolerance(E2);
2279       }
2280     }
2281
2282     TTSS->Append(E2);
2283     
2284     if ( newtol > MaxTolerance() ) 
2285       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
2286     
2287     ShapeExtend_WireData sewd;
2288     for (Standard_Integer i=1 ; i <= TTSS->Length(); i++) {
2289       sewd.Add(TopoDS::Edge(TTSS->Value(i)));
2290     }
2291     if (! Context().IsNull()) {
2292       Context()->Replace ( E, sewd.Wire() );
2293       UpdateWire();
2294     }
2295     else {
2296       WireData()->Remove(num >0 ? num : NbEdges());
2297       WireData()->Add(sewd.Wire(), num >0 ? num : NbEdges());
2298     }
2299     if (loopRemoved)
2300       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
2301     
2302   }
2303
2304   if ( LastFixStatus ( ShapeExtend_DONE ) && ! myShape.IsNull() ) {
2305     SendWarning ( E, Message_Msg ( "FixAdvWire.FixIntersection.MSG5" ) );// Edge was self-intersecting, corrected
2306   }
2307
2308   return LastFixStatus ( ShapeExtend_DONE );
2309 }
2310
2311
2312 //=======================================================================
2313 //function : ComputeLocalDeviation
2314 //purpose  : auxilary
2315 //=======================================================================
2316 static Standard_Real ComputeLocalDeviation (const TopoDS_Edge &edge, 
2317                                             const gp_Pnt &pint,const gp_Pnt &pnt,
2318                                             Standard_Real f, Standard_Real l,
2319                                             const TopoDS_Face &face )
2320 {
2321   ShapeAnalysis_Edge sae;
2322   Handle(Geom_Curve) c3d;
2323   Standard_Real a, b;
2324   if ( ! sae.Curve3d ( edge, c3d, a, b, Standard_False ) ) return RealLast();
2325   
2326   gp_Lin line ( pint, gp_Vec ( pint, pnt ) );
2327   
2328   Handle(Geom2d_Curve) Crv;
2329   Standard_Real fp,lp;
2330   if ( sae.PCurve(edge,face,Crv,fp,lp,Standard_False) ) {
2331     if(Crv->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) {
2332       Handle(Geom2d_TrimmedCurve) tc = Handle(Geom2d_TrimmedCurve)::DownCast(Crv);
2333       if(tc->BasisCurve()->IsKind(STANDARD_TYPE(Geom2d_Line))) {
2334         f = a + (f-fp)*(b-a)/(lp-fp);
2335         l = a + (l-fp)*(b-a)/(lp-fp);
2336       }
2337     }
2338   }
2339
2340   const Standard_Integer NSEG = 10;
2341   Standard_Real step = ( l - f ) / NSEG;
2342   Standard_Real dev = 0.;
2343   for ( Standard_Integer i=1; i < NSEG; i++ ) {
2344     gp_Pnt p = c3d->Value ( f + i * step );
2345     Standard_Real d = line.Distance ( p );
2346     if ( dev < d ) dev = d;
2347   }
2348   return dev;
2349 }
2350
2351 //=======================================================================
2352 //function : FixIntersectingEdges
2353 //purpose  : 
2354 //=======================================================================
2355
2356 Standard_Boolean ShapeFix_Wire::FixIntersectingEdges (const Standard_Integer num) 
2357 {
2358   myLastFixStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
2359   if ( ! IsReady() || NbEdges() <2 ) return Standard_False;
2360
2361   // analysis
2362   IntRes2d_SequenceOfIntersectionPoint points2d;
2363   TColgp_SequenceOfPnt points3d;
2364   TColStd_SequenceOfReal errors;
2365   Handle(ShapeAnalysis_Wire) theAdvAnalyzer = Handle(ShapeAnalysis_Wire)::DownCast(myAnalyzer);
2366   if (theAdvAnalyzer.IsNull()) return Standard_False;
2367   theAdvAnalyzer->CheckIntersectingEdges ( num, points2d, points3d, errors );
2368   if ( theAdvAnalyzer->LastCheckStatus ( ShapeExtend_FAIL ) ) {
2369     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
2370   }
2371   if ( ! theAdvAnalyzer->LastCheckStatus ( ShapeExtend_DONE ) ) return Standard_False;
2372   
2373   //rln 03/02/98: CSR#BUC50004 entity 56 (to avoid later inserting lacking edge)
2374   //:l0  Standard_Boolean isLacking = myAnalyzer->CheckLacking ( num );
2375
2376   // action: increase tolerance of vertex
2377   
2378   Handle(ShapeExtend_WireData) sbwd = WireData();
2379   Standard_Integer n2 = ( num >0 ? num  : sbwd->NbEdges() );
2380   Standard_Integer n1 = ( n2  >1 ? n2-1 : sbwd->NbEdges() );
2381   TopoDS_Edge E1 = sbwd->Edge(n1);
2382   TopoDS_Edge E2 = sbwd->Edge(n2);
2383   Standard_Boolean isForward1 = ( E1.Orientation() == TopAbs_FORWARD );
2384   Standard_Boolean isForward2 = ( E2.Orientation() == TopAbs_FORWARD );
2385   Standard_Real a1, b1, a2, b2;
2386   BRep_Tool::Range ( E1, Face(), a1, b1 );
2387   BRep_Tool::Range ( E2, Face(), a2, b2 );
2388   
2389   ShapeAnalysis_Edge sae;
2390   TopoDS_Vertex Vp = sae.FirstVertex ( E1 );
2391   TopoDS_Vertex V1 = sae.LastVertex  ( E1 );
2392   TopoDS_Vertex V2 = sae.FirstVertex ( E2 );
2393   TopoDS_Vertex Vn = sae.LastVertex  ( E2 );
2394
2395   Standard_Real tol = BRep_Tool::Tolerance ( V1 );
2396   gp_Pnt pnt = BRep_Tool::Pnt ( V1 );
2397   
2398   Standard_Real prevRange1 = RealLast(), prevRange2 = RealLast();
2399   Standard_Boolean cutEdge1 = Standard_False, cutEdge2 = Standard_False;
2400   Standard_Boolean IsCutLine = Standard_False;
2401
2402   BRep_Builder B;
2403   
2404   Standard_Integer nb = points3d.Length();
2405   for ( Standard_Integer i=1; i <= nb; i++ ) {
2406     const IntRes2d_IntersectionPoint &IP = points2d.Value(i);
2407     Standard_Real param1 = ( num ==1 ? IP.ParamOnSecond() : IP.ParamOnFirst() );
2408     Standard_Real param2 = ( num ==1 ? IP.ParamOnFirst()  : IP.ParamOnSecond() );
2409     
2410     Standard_Real newRange1 = Abs ( ( isForward1 ? a1 : b1 ) - param1 );
2411     Standard_Real newRange2 = Abs ( ( isForward2 ? b2 : a2 ) - param2 );
2412     if ( newRange1 > prevRange1 && newRange2 > prevRange2 ) continue;
2413     
2414     gp_Pnt pint = points3d.Value(i);
2415     Standard_Real rad = errors.Value(i);
2416     Standard_Real newtol = 1.0001 * ( pnt.Distance ( pint ) + rad );
2417
2418     //GeomAdaptor_Surface& Ads = myAnalyzer->Surface()->Adaptor3d()->ChangeSurface();
2419
2420     //:r8 abv 12 Apr 99: try increasing tolerance of edge
2421
2422     Standard_Boolean locMayEdit = myTopoMode;
2423     // Always try to modify the tolerance firstly as a better solution
2424     if ( /*! myTopoMode &&*/ newtol > tol ) {
2425       Standard_Real te1 = rad + ComputeLocalDeviation (E1, pint, pnt,
2426         param1, ( isForward1 ? b1 : a1 ), Face() );
2427       Standard_Real te2 = rad + ComputeLocalDeviation (E2, pint, pnt, 
2428         ( isForward2 ? a2 : b2 ), param2, Face() );
2429       Standard_Real maxte = Max ( te1, te2 );
2430       if ( maxte < MaxTolerance() && maxte < newtol ) {
2431         if ( BRep_Tool::Tolerance(E1) < te1 || BRep_Tool::Tolerance(E2) < te2 ) {
2432 #ifdef OCCT_DEBUG
2433           cout << "Warning: ShapeFix_Wire::FixIE: edges tolerance increased: (" <<
2434             te1 << ", " << te2 << ") / " << newtol << endl;
2435 #endif
2436           B.UpdateEdge ( E1, 1.000001 * te1 );
2437           B.UpdateVertex ( sae.FirstVertex ( E1 ), 1.000001 * te1 );
2438           B.UpdateVertex ( sae.LastVertex  ( E1 ), 1.000001 * te1 );
2439           B.UpdateEdge ( E2, 1.000001 * te2 );
2440           B.UpdateVertex ( sae.FirstVertex ( E2 ), 1.000001 * te2 );
2441           B.UpdateVertex ( sae.LastVertex  ( E2 ), 1.000001 * te2 );
2442
2443           myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE6 );
2444           locMayEdit = Standard_False;
2445         }
2446         newtol = 1.000001 * maxte;
2447       }
2448     }
2449     
2450     if ( locMayEdit || newtol <= MaxTolerance() )
2451     {
2452       prevRange1 = newRange1; 
2453       prevRange2 = newRange2;
2454       if ( locMayEdit )
2455       {
2456         newtol = 1.0001 * ( pnt.Distance ( pint ) + rad );
2457         //:j6 abv 7 Dec 98: ProSTEP TR10 r0601_id.stp #57676 & #58586: do not cut edges because of influence on adjacent faces
2458         ShapeFix_SplitTool aTool;
2459         
2460         if ( ! aTool.CutEdge ( E1, ( isForward1 ? a1 : b1 ), param1, Face(), IsCutLine ) ) {
2461           if ( V1.IsSame ( Vp ) )
2462             myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
2463           else locMayEdit = Standard_False;
2464         }
2465         else cutEdge1 = Standard_True; //:h4
2466         
2467         if ( ! aTool.CutEdge ( E2, ( isForward2 ? b2 : a2 ), param2, Face(), IsCutLine ) ) {
2468           if ( V2.IsSame ( Vn ) ) 
2469             myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
2470           else locMayEdit = Standard_False;
2471         }
2472         else cutEdge2 = Standard_True; //:h4
2473       }
2474
2475       if (  locMayEdit &&
2476             newRange1 <= prevRange1 && newRange2 <= prevRange2 && //rln 09/01/98
2477             BRep_Tool::SameParameter ( E1 ) &&
2478             BRep_Tool::SameParameter ( E2 ) )
2479       {
2480         myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
2481         pnt = pint;
2482         if ( tol <= rad ) {
2483           myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
2484           tol = 1.001 * rad;
2485         }
2486       }
2487       else
2488       {
2489         if(IsCutLine)
2490         {
2491           myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
2492           pnt = pint;
2493           if ( tol <= rad ) {
2494             myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
2495             tol = 1.001 * rad;
2496           }
2497         }
2498         else
2499         { // else increase tolerance
2500           if (tol < newtol)
2501           { //rln 07.04.99 CCI60005-brep.igs
2502             myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
2503             tol = newtol;
2504           }
2505         }
2506       }
2507     }
2508     else
2509     {
2510       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
2511     }
2512   }
2513
2514   if ( ! LastFixStatus ( ShapeExtend_DONE ) ) return Standard_False;
2515
2516   B.UpdateVertex ( V1, pnt, tol );
2517   B.UpdateVertex ( V2, pnt, tol );
2518
2519   //:h4: make edges SP (after all cuts: t4mug.stp #3730+#6460)
2520   if ( cutEdge1 ) myFixEdge->FixSameParameter ( E1 );
2521   if ( cutEdge2 && !IsCutLine ) myFixEdge->FixSameParameter ( E2 );
2522   if ( cutEdge1 || cutEdge2 ) {
2523     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
2524   }
2525   if ( ! myShape.IsNull() ) {
2526     SendWarning ( Message_Msg ( "FixAdvWire.FixIntersection.MSG10" ) );// Edges were intersecting, corrected
2527   }
2528   return Standard_True;
2529 }
2530
2531 //=======================================================================
2532 //function : FixIntersectingEdges
2533 //purpose  : 
2534 //=======================================================================
2535 //pdn 17.03.99 fixing non ajacent intersection by increasing tolerance of vertex
2536
2537 Standard_Boolean ShapeFix_Wire::FixIntersectingEdges (const Standard_Integer num1,
2538                                                       const Standard_Integer num2)
2539 {
2540   myLastFixStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
2541   if ( !IsReady() ) return Standard_False;
2542   IntRes2d_SequenceOfIntersectionPoint points2d;
2543   TColgp_SequenceOfPnt points3d;
2544   TColStd_SequenceOfReal errors;
2545   Handle(ShapeAnalysis_Wire) theAdvAnalyzer = Handle(ShapeAnalysis_Wire)::DownCast(myAnalyzer);
2546   if (theAdvAnalyzer.IsNull()) return Standard_False;
2547   theAdvAnalyzer->CheckIntersectingEdges ( num1, num2, points2d, points3d, errors);
2548   if ( theAdvAnalyzer->LastCheckStatus ( ShapeExtend_FAIL ) ) {
2549     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
2550   }
2551   if ( ! theAdvAnalyzer->LastCheckStatus ( ShapeExtend_DONE ) ) return Standard_False;
2552   TColgp_Array1OfPnt vertexPoints(1,4);
2553   TColStd_Array1OfReal vertexTolers(1,4);
2554   TColStd_Array1OfReal newTolers(1,4);
2555   TopTools_Array1OfShape vertices(1,4);
2556   newTolers.Init(0);
2557   
2558   Handle(ShapeExtend_WireData) sbwd = WireData();
2559   Standard_Integer n2 = ( num1 >0 ? num1  : sbwd->NbEdges() );
2560   Standard_Integer n1 = ( num2  >1 ? num2 : sbwd->NbEdges() );
2561   if(n1==n2) return Standard_False;
2562   
2563   TopoDS_Edge edge1 = sbwd->Edge(n1);
2564   TopoDS_Edge edge2 = sbwd->Edge(n2);
2565   
2566   ShapeAnalysis_Edge sae;
2567   vertices(1) = sae.FirstVertex(edge1);
2568   vertices(2) = sae.LastVertex(edge1);
2569   vertices(3) = sae.FirstVertex(edge2);
2570   vertices(4) = sae.LastVertex(edge2);
2571   
2572   Standard_Integer i; // svv Jan11 2000 : porting on DEC
2573   for (i = 1; i <=4; i++) {
2574     vertexPoints(i) = BRep_Tool::Pnt(TopoDS::Vertex(vertices(i)));
2575     vertexTolers(i) = BRep_Tool::Tolerance(TopoDS::Vertex(vertices(i)));
2576   }
2577    
2578   Standard_Real aNewTolEdge1 = 0.0, aNewTolEdge2 = 0.0;
2579   Standard_Integer nb = points3d.Length();
2580   for ( i=1; i <= nb; i++ ) {
2581     gp_Pnt pint = points3d.Value(i);
2582
2583     // searching for the nearest vertexies to the intersection point
2584     Standard_Real aVtx1Param=0., aVtx2Param=0.;
2585     Standard_Integer aVC1, aVC2;
2586     Standard_Real aMinDist = RealLast();
2587     gp_Pnt aNearestVertex;
2588     Standard_Real aNecessaryVtxTole = 0.0;
2589     for(aVC1 = 1; aVC1 <= 2; aVC1++) {
2590       for(aVC2 = 3; aVC2 <= 4; aVC2++) {
2591       
2592         Standard_Real aVtxIPDist = pint.Distance(vertexPoints(aVC1));
2593         Standard_Real aVtxVtxDist = vertexPoints(aVC1).Distance(vertexPoints(aVC2));
2594         if(aMinDist > aVtxIPDist && aVtxIPDist > aVtxVtxDist) {
2595           aNecessaryVtxTole = aVtxVtxDist;
2596           aNearestVertex = vertexPoints(aVC1);
2597           aMinDist = aVtxIPDist;
2598           aVtx1Param = BRep_Tool::Parameter(TopoDS::Vertex(vertices(aVC1)),edge1);
2599           aVtx2Param = BRep_Tool::Parameter(TopoDS::Vertex(vertices(aVC2)),edge2);
2600         }
2601       }
2602     }
2603     
2604     // calculation of necessary tolerances of edges
2605     const IntRes2d_IntersectionPoint &IP = points2d.Value(i);
2606     Standard_Real param1 = IP.ParamOnFirst(); 
2607     Standard_Real param2 = IP.ParamOnSecond();  
2608     Handle(Geom_Curve) aCurve1, aCurve2;
2609     Standard_Real f,l;
2610     TopLoc_Location L1, L2;
2611     aCurve1 = BRep_Tool::Curve(edge1, L1, f, l);
2612     aCurve2 = BRep_Tool::Curve(edge2, L2, f, l);
2613     
2614     // if aMinDist lower than resolution than the intersection point lyes inside the vertex
2615     if(aMinDist < gp::Resolution())
2616       continue;
2617     
2618     Standard_Real aMaxEdgeTol1 = 0.0, aMaxEdgeTol2 = 0.0;
2619     if(aMinDist < RealLast() && !aCurve1.IsNull() && !aCurve2.IsNull())
2620     {
2621       gp_Lin aLig(aNearestVertex, gp_Vec(aNearestVertex, pint));
2622       Standard_Integer aPointsC;
2623       Standard_Real du1 = 0.05*(param1 - aVtx1Param);
2624       Standard_Real du2 = 0.05*(param2 - aVtx2Param);
2625       Standard_Real tole1=BRep_Tool::Tolerance(edge1);
2626       Standard_Real tole2=BRep_Tool::Tolerance(edge2);
2627       for(aPointsC = 2; aPointsC < 19; aPointsC++)
2628       {
2629         Standard_Real u = aVtx1Param + aPointsC * du1;
2630         gp_Pnt P1 = aCurve1->Value(u);
2631         P1.Transform(L1.Transformation());
2632         Standard_Real d1 = aLig.Distance(P1) * 2.0000001;
2633         if(d1 > tole1 && d1 > aMaxEdgeTol1)
2634           aMaxEdgeTol1 = d1;
2635
2636         u = aVtx2Param + aPointsC * du2;
2637         gp_Pnt P2 = aCurve2->Value(u);
2638         P2.Transform(L2.Transformation());
2639         Standard_Real d2 = aLig.Distance(P2) * 2.0000001;
2640         if(d2 > tole2 && d2 > aMaxEdgeTol2)
2641           aMaxEdgeTol2 = d2;
2642       }
2643       if(aMaxEdgeTol1 == 0.0 && aMaxEdgeTol2 == 0.0) continue;
2644       // if the vertexies are far than tolerances so 
2645       // we do not need to increase edge tolerance
2646       if(aNecessaryVtxTole > Max(aMaxEdgeTol1, tole1) ||
2647          aNecessaryVtxTole > Max(aMaxEdgeTol2, tole2))
2648       {
2649         aMaxEdgeTol1 = 0.0;
2650         aMaxEdgeTol2 = 0.0;
2651       }
2652     }
2653     
2654     Standard_Real rad = errors.Value(i);
2655     Standard_Real finTol = RealLast();
2656     Standard_Integer rank=1;
2657     for(Standard_Integer j=1; j<=4; j++) {
2658       Standard_Real newtol = 1.0001 * ( pint.Distance (vertexPoints(j)) + rad );
2659       if(newtol<finTol) {
2660         rank = j;
2661         finTol = newtol;
2662       }
2663     }
2664     if(finTol <= MaxTolerance()) {
2665       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1);
2666       if(newTolers(rank) < finTol)
2667       {
2668         if(Max(aMaxEdgeTol1, aMaxEdgeTol2) < finTol && (aMaxEdgeTol1 > 0 || aMaxEdgeTol2 > 0))
2669         {
2670           aNewTolEdge1 = Max(aNewTolEdge1, aMaxEdgeTol1);
2671           aNewTolEdge2 = Max(aNewTolEdge2, aMaxEdgeTol2);
2672         }
2673         else
2674         {
2675           newTolers(rank) = finTol;
2676         }
2677       }
2678     } else {
2679       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
2680     }
2681   }
2682   
2683   BRep_Builder B;
2684   // update of tolerances of edges 
2685   if(aNewTolEdge1 > 0)
2686   {
2687     for(i = 1; i <= 2; i++)
2688       if(aNewTolEdge1 > Max(vertexTolers(i), newTolers(i)))
2689         newTolers(i) = aNewTolEdge1;
2690     B.UpdateEdge(edge1, aNewTolEdge1);
2691   }
2692   if(aNewTolEdge2 > 0)
2693   {
2694     for(i = 3; i <= 4; i++)
2695       if(aNewTolEdge2 > Max(vertexTolers(i), newTolers(i)))
2696         newTolers(i) = aNewTolEdge2;
2697     B.UpdateEdge(edge2, aNewTolEdge2);
2698   }
2699     
2700   // update of tolerances of vertexies 
2701   for(i = 1; i <=4; i++)
2702     if(newTolers(i)>0) B.UpdateVertex(TopoDS::Vertex(vertices(i)),newTolers(i));
2703   
2704   if ( ! myShape.IsNull() ) {
2705     SendWarning ( Message_Msg ( "FixAdvWire.FixIntersection.MSG10" ) );// Edges were intersecting, corrected
2706   }
2707   return Standard_True;
2708 }
2709
2710 //=======================================================================
2711 //function : FixLacking
2712 //purpose  : Test if two adjucent edges are disconnected in 2d (while connected 
2713 //           in 3d), and in that case either increase tolerance of the vertex or
2714 //           add a new edge (straight in 2d space), in order to close wire in 2d.
2715 //           Returns True if edge was added or tolerance was increased.
2716 //NOTE     : Is to be run after FixDegenerated
2717 //Algorithm: 1. Compute the 2d gap between edges and calculate a tolerance
2718 //              which should have vertex in order to comprise the gap
2719 //              (using GeomAdaptor_Surface); computed value is inctol
2720 //           2. If inctol < tol of vertex, return False (everything is OK)
2721 //           3. If inctol < Precision, just increase tolerance of vertex to inctol
2722 //           4. Else (if both edges are not degenerated) try to add new edge 
2723 //              with straight pcurve (in order to close the gap):
2724 //              a) if flag MayEdit is False
2725 //                 1. if inctol < MaxTolerance, increase tolerance of vertex to inctol
2726 //                 2. else try to add degenerated edge (check that middle point of 
2727 //                    that pcurveis inside the vertex)
2728 //              b) if MayEdit is True
2729 //                 1. try to replace big vertex with two new small vertices 
2730 //                    connected by new edge. This is made if there is a 3d space
2731 //                    between ends of adjacent edges.
2732 //                 2. if inctol < MaxTolerance, increase tolerance of vertex to inctol
2733 //                 3. else add either degenerated or closed edge (if middle point
2734 //                    of a pcurve of a new edge is inside the vertex, then
2735 //                    degenerated edge is added, else new edge is closed).
2736 //           5. If new edge cannot be added, but inctol < MaxTolerance,
2737 //              when increase tolerance of vertex to a value of inctol
2738 //Short list of some internal variables:
2739 // tol    - tolerance of vertex
2740 // tol2d  - tolerance in parametric space of the surface corresponding to 2*tol
2741 // dist2d - distance between ends of pcurves of edges (2d)
2742 // inctol - tolerance required for vertex to close 2d gap (=tol*dist2d/tol2d)
2743 // tol1, tol2 - tolerances of edges, tol0 = tol1 + tol2
2744 // p3d1, p3d2 - ends of 3d curves of edges
2745 //=======================================================================
2746 //:h2 abv 28 May 98: merged modifications by abv 22 Apr 98, gka 27 May 98 
2747 // and pdn 25 May 98 concerning lacking closed or degenerated edges
2748 // Example files: r0501_pe #107813, UKI60107-6 250, UKI60107-3 1577.
2749
2750 //:s2 abv 21 Apr 99: add functionality for bending pcurve
2751 static Standard_Boolean TryBendingPCurve (const TopoDS_Edge &E, const TopoDS_Face &face,
2752                                           const gp_Pnt2d p2d, const Standard_Boolean end,
2753                                           Handle(Geom2d_Curve) &c2d,
2754                                           Standard_Real &first, Standard_Real &last,
2755                                           Standard_Real &tol)
2756 {
2757   ShapeAnalysis_Edge sae;
2758   if ( ! sae.PCurve ( E, face, c2d, first, last, Standard_False ) ) return Standard_False;
2759   
2760   {
2761   try {
2762     OCC_CATCH_SIGNALS
2763     Handle(Geom2d_BSplineCurve) bs;
2764     if ( c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) ) 
2765       bs = Handle(Geom2d_BSplineCurve)::DownCast(c2d->Copy());
2766     else // if ( c2d->IsKind(STANDARD_TYPE(Geom2d_Line)) ) 
2767     {
2768       Handle(Geom2d_TrimmedCurve) trim = new Geom2d_TrimmedCurve ( c2d, first, last );
2769       bs = Geom2dConvert::CurveToBSplineCurve ( trim );
2770     }
2771     if ( bs.IsNull() ) return Standard_False;
2772   
2773     Standard_Real par = ( end ? last : first );
2774     if ( fabs ( bs->FirstParameter() - par ) < ::Precision::PConfusion() &&
2775         bs->Multiplicity(1) > bs->Degree() ) bs->SetPole ( 1, p2d );
2776     else if ( fabs ( bs->LastParameter() - par ) < ::Precision::PConfusion() &&
2777              bs->Multiplicity(bs->NbKnots()) > bs->Degree() ) bs->SetPole ( bs->NbPoles(), p2d );
2778     else {
2779       bs->Segment ( first, last );
2780       if (fabs ( bs->FirstParameter() - par ) < ::Precision::PConfusion() &&
2781           bs->Multiplicity(1) > bs->Degree()) bs->SetPole ( 1, p2d );
2782       else if (fabs ( bs->LastParameter() - par ) < ::Precision::PConfusion() &&
2783                bs->Multiplicity(bs->NbKnots()) > bs->Degree()) bs->SetPole ( bs->NbPoles(), p2d );
2784       else return Standard_False;
2785     }
2786     c2d = bs;
2787
2788     if ( ! TryNewPCurve ( E, face, c2d, first, last, tol ) ) return Standard_False;
2789   }
2790   catch ( Standard_Failure ) {
2791 #ifdef OCCT_DEBUG
2792     cout << "Warning: ShapeFix_Wire::FixLacking: Exception in Geom2d_BSplineCurve::Segment()" << endl;
2793 #endif
2794     return Standard_False;
2795   }
2796   }
2797
2798   return Standard_True;
2799 }
2800
2801
2802 //=======================================================================
2803 //function : FixLacking
2804 //purpose  : 
2805 //=======================================================================
2806
2807 Standard_Boolean ShapeFix_Wire::FixLacking (const Standard_Integer num,
2808                                             const Standard_Boolean force) 
2809 {
2810     myLastFixStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
2811   if ( ! IsReady() ) return Standard_False;
2812
2813   //=============
2814   // First phase: analysis whether the problem (gap) exists
2815   gp_Pnt2d p2d1, p2d2;
2816   Handle(ShapeAnalysis_Wire)::DownCast(myAnalyzer)->CheckLacking ( num, ( force ? Precision() : 0. ), p2d1, p2d2 );
2817   if ( myAnalyzer->LastCheckStatus ( ShapeExtend_FAIL ) ) {
2818     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
2819   }
2820   if ( ! myAnalyzer->LastCheckStatus ( ShapeExtend_DONE ) ) return Standard_False;
2821   
2822   //=============
2823   // Second phase: collection of data necessary for further analysis
2824   
2825   Handle(ShapeExtend_WireData) sbwd = WireData();
2826   Standard_Integer n2 = ( num >0 ? num  : sbwd->NbEdges() );
2827   Standard_Integer n1 = ( n2  >1 ? n2-1 : sbwd->NbEdges() );
2828   TopoDS_Edge E1 = sbwd->Edge(n1);
2829   TopoDS_Edge E2 = sbwd->Edge(n2);
2830   
2831   ShapeAnalysis_Edge sae;
2832   TopoDS_Vertex V1 = sae.LastVertex  ( E1 );
2833   TopoDS_Vertex V2 = sae.FirstVertex ( E2 );
2834   Standard_Real tol = Max ( BRep_Tool::Tolerance ( V1 ), BRep_Tool::Tolerance ( V2 ) );
2835   
2836   Standard_Real Prec = Precision();
2837   Standard_Real dist2d = myAnalyzer->MaxDistance2d();
2838   Standard_Real inctol = myAnalyzer->MaxDistance3d();
2839   
2840   TopoDS_Face face = myAnalyzer->Face();
2841   Handle(ShapeAnalysis_Surface) surf = myAnalyzer->Surface();
2842
2843   gp_Pnt p3d1, p3d2;
2844   Standard_Real tol1=::Precision::Confusion(), tol2=::Precision::Confusion(); //SK
2845
2846   //=============
2847   //:s2 abv 21 Apr 99: Speculation: try bending pcurves
2848   Standard_Real bendtol1 = 0., bendtol2 = 0.;
2849   Handle(Geom2d_Curve) bendc1, bendc2;
2850   Standard_Real bendf1 = 0., bendl1 = 0., bendf2 = 0., bendl2 = 0.;
2851   if ( myGeomMode && ! BRep_Tool::IsClosed(E1,face) && ! BRep_Tool::IsClosed(E2,face) ) {
2852     gp_Pnt2d p2d = 0.5 * ( p2d1.XY() + p2d2.XY() );
2853     Standard_Boolean ok1 = TryBendingPCurve (E1, face, p2d, E1.Orientation() == TopAbs_FORWARD, 
2854                                              bendc1, bendf1, bendl1, bendtol1);
2855     Standard_Boolean ok2 = TryBendingPCurve (E2, face, p2d, E2.Orientation() == TopAbs_REVERSED, 
2856                                              bendc2, bendf2, bendl2, bendtol2);
2857     if ( ok1 && ! ok2 ) {
2858       bendtol2 = BRep_Tool::Tolerance(E2);
2859       ok1 = TryBendingPCurve (E1, face, p2d2, E1.Orientation() == TopAbs_FORWARD, 
2860                               bendc1, bendf1, bendl1, bendtol1);
2861     }
2862     else if ( ! ok1 && ok2 ) {
2863       bendtol1 = BRep_Tool::Tolerance(E1);
2864       ok2 = TryBendingPCurve (E2, face, p2d1, E2.Orientation() == TopAbs_FORWARD, 
2865                               bendc2, bendf2, bendl2, bendtol2);
2866     }
2867     if ( ! ok1 && ! ok2 ) bendc1.Nullify();
2868   }
2869   
2870   //=============
2871   // Third phase: analyse how to fix the problem
2872   
2873   // selector of solutions
2874   Standard_Boolean doIncrease  = Standard_False; // increase tolerance
2875   Standard_Boolean doAddLong   = Standard_False; // add long 3d edge in replacement of a vertex
2876   Standard_Boolean doAddClosed = Standard_False; // add closed 3d edge
2877   Standard_Boolean doAddDegen  = Standard_False; // add degenerated edge
2878   Standard_Boolean doBend      = Standard_False; //:s2 bend pcurves
2879
2880   // if bending is OK with existing tolerances of edges, take it
2881   if ( ! bendc1.IsNull() && ! bendc2.IsNull() &&
2882        ( ( bendtol1 < BRep_Tool::Tolerance(E1) &&
2883            bendtol2 < BRep_Tool::Tolerance(E2) ) ||
2884          ( inctol < Prec && bendtol1 < inctol && bendtol2 < inctol ) ) ) 
2885        doBend = Standard_True;
2886   
2887   // is it OK just to increase tolerance (to a value less than preci)?
2888   else if ( inctol < Prec ) doIncrease = Standard_True;
2889
2890   // If increase is not OK or force, try to find other solutions (adding edge)
2891   else if ( ! BRep_Tool::Degenerated ( E2 ) && ! BRep_Tool::Degenerated ( E1 ) ) {
2892     
2893     // analyze the 3d space btw edges: is it enough to add long 3d edge?
2894     if ( myTopoMode ) {
2895       Handle(Geom_Curve) c3d;
2896       Standard_Real a, b;
2897       if ( ! sae.Curve3d ( E1, c3d, a, b, Standard_True ) ) { // cannot work
2898         myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
2899         return Standard_False; 
2900       }
2901       p3d1 = c3d->Value ( b );
2902       Standard_Real dist2d3d1 = p3d1.Distance ( surf->Value ( p2d1 ) );
2903       if ( ! sae.Curve3d ( E2, c3d, a, b, Standard_True ) ) { // cannot work
2904         myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
2905         return Standard_False; 
2906       }
2907       p3d2 = c3d->Value ( a );
2908       Standard_Real dist2d3d2 = p3d2.Distance ( surf->Value ( p2d2 ) );
2909
2910       tol1 = Max ( BRep_Tool::Tolerance ( E1 ), dist2d3d1 );
2911       tol2 = Max ( BRep_Tool::Tolerance ( E2 ), dist2d3d2 );
2912       //:c5  Standard_Real tol0 = Max ( tol1 + tol2, thepreci );
2913       Standard_Real tol0 = tol1 + tol2; //:c5 abv 26 Feb 98: CTS17806 #44418
2914       Standard_Real dist3d2 = p3d1.SquareDistance ( p3d2 );
2915
2916       // is it OK to add a long 3d edge?
2917       if ( ! myAnalyzer->LastCheckStatus ( ShapeExtend_DONE2 ) && //:81 abv 20 Jan 98: don`t add back-going edges (zigzags)
2918            dist3d2 > 1.25 * tol0 * tol0 &&
2919            ( force || dist3d2 > Prec * Prec || inctol > MaxTolerance() ) ) {
2920         doAddLong = Standard_True;
2921       }
2922     }
2923     
2924     //:h6 abv 25 Jun 98: BUC40132 6361: try to increase tol up to MaxTol if not add
2925     if ( ! doAddLong && inctol < MaxTolerance() && 
2926          ! myAnalyzer->Surface()->IsDegenerated ( p2d1, p2d2, 2.*tol, 10. ) ) { //:p7
2927       if ( ! bendc1.IsNull() && ! bendc2.IsNull() &&
2928            bendtol1 < inctol && bendtol2 < inctol ) doBend = Standard_True;
2929       else doIncrease = Standard_True;
2930     }
2931     else 
2932       
2933     // else try to add either degenerated or closed edge
2934     if ( ! doAddLong ) {
2935       gp_Pnt pV = 0.5 * ( BRep_Tool::Pnt(V1).XYZ() + BRep_Tool::Pnt(V2).XYZ() );
2936       gp_Pnt pm = myAnalyzer->Surface()->Value ( 0.5 * ( p2d1.XY() + p2d2.XY() ) );
2937
2938       Standard_Real dist = pV.Distance ( pm );
2939       if ( dist <= tol ) doAddDegen = Standard_True;
2940       else if ( myTopoMode ) doAddClosed = Standard_True;
2941       else if ( dist <= MaxTolerance() ) { //:r7 abv 12 Apr 99: t3d_opt.stp #14245 after S4136
2942         doAddDegen = Standard_True;
2943         doIncrease = Standard_True;
2944         inctol = dist; 
2945       }
2946     }
2947   }
2948
2949   else if ( !BRep_Tool::Degenerated(E2) && BRep_Tool::Degenerated(E1) ) {
2950     // create new degenerated edge and replace E1 to new edge
2951   }
2952   else if ( BRep_Tool::Degenerated(E2) && !BRep_Tool::Degenerated(E1) ) {
2953     // create new degenerated edge and replace E2 to new edge
2954   }
2955   
2956   //=============
2957   // Third phase - do the fixes
2958   BRep_Builder B;
2959
2960   // add edge
2961   if ( doAddLong || doAddDegen || doAddClosed ) {
2962
2963     // construct new vertices
2964     TopoDS_Vertex newV1, newV2;
2965     if ( doAddLong ) {
2966       newV1 = BRepBuilderAPI_MakeVertex ( p3d1 );
2967       newV1.Reverse();
2968       newV2 = BRepBuilderAPI_MakeVertex ( p3d2 );
2969       B.UpdateVertex ( newV1, 1.001 * tol1 );
2970       B.UpdateVertex ( newV2, 1.001 * tol2 );
2971     }
2972     else {
2973       newV1 = V1;
2974       newV2 = V2;
2975     }
2976
2977     // prepare new edge
2978     TopoDS_Edge edge;
2979     B.MakeEdge ( edge );
2980     if ( doAddDegen ) B.Degenerated ( edge, Standard_True ); // sln: do it before adding curve
2981     gp_Vec2d v12 ( p2d1, p2d2 );
2982     Handle(Geom2d_Line) theLine2d = new Geom2d_Line ( p2d1, gp_Dir2d ( v12 ) );
2983     B.UpdateEdge ( edge, theLine2d, face, ::Precision::Confusion() );
2984     B.Range ( edge, face, 0, dist2d );
2985     B.Add ( edge, newV1.Oriented ( TopAbs_FORWARD ) );
2986     B.Add ( edge, newV2.Oriented ( TopAbs_REVERSED ) );
2987     ShapeBuild_Edge sbe;
2988     if ( ! doAddDegen && ! sbe.BuildCurve3d ( edge ) ) {
2989       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL3 );
2990       return Standard_False; 
2991     }
2992
2993     // if long edge is added, replace vertices of adjacent edges
2994     if ( doAddLong ) {
2995       
2996       // replace 1st edge (n1==n2 - special case: wire consists of one edge)
2997       TopoDS_Edge edge1 = sbe.CopyReplaceVertices ( E1, 
2998                           ( n1 == n2 ? newV2 : TopoDS_Vertex() ), newV1 );
2999       sbwd->Set ( edge1, n1 );
3000       if ( ! Context().IsNull() ) {
3001         Context()->Replace ( E1, edge1 );
3002         // actually, this will occur only in context of single face
3003         // hence, recording to ReShape is rather for tracking modifications
3004         // than for keeping sharing
3005         Context()->Replace ( V1, newV1.Oriented ( V1.Orientation() ) );
3006         if ( ! V1.IsSame ( V2 ) ) { 
3007           Context()->Replace ( V2, newV2.Oriented ( V2.Orientation() ) );
3008         }
3009       }
3010       // replace 2nd edge
3011       if ( n1 != n2 ) {
3012         TopoDS_Edge edge2 = sbe.CopyReplaceVertices ( E2, newV2, TopoDS_Vertex() );
3013         sbwd->Set ( edge2, n2 );
3014         if ( ! Context().IsNull() ) Context()->Replace ( E2, edge2 );
3015       }
3016       if ( ! Context().IsNull() ) UpdateWire();
3017     }
3018
3019     // insert new edge
3020     if ( doAddDegen ) {
3021       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
3022 #ifdef OCCT_DEBUG
3023       cout << "Warning: ShapeFix_Wire::FixLacking: degenerated edge added" << endl;
3024 #endif
3025     }
3026     else if ( ! doAddLong ) {
3027       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
3028     }
3029     sbwd->Add ( edge, n2 );
3030     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
3031   }
3032   
3033   // else try to increase tol up to MaxTol
3034   else if ( inctol > tol && inctol < MaxTolerance() ) {
3035     if ( ! bendc1.IsNull() && ! bendc2.IsNull() &&
3036          bendtol1 < inctol && bendtol2 < inctol ) doBend = Standard_True;
3037     else doIncrease = Standard_True;
3038   }
3039   
3040   // bend pcurves
3041   if ( doBend ) { //:s2 abv 21 Apr 99
3042     B.UpdateEdge ( E1, bendc1, face, bendtol1 );
3043     B.Range ( E1, face, bendf1, bendl1 );
3044     B.UpdateEdge ( E2, bendc2, face, bendtol2 );
3045     B.Range ( E2, face, bendf2, bendl2 );
3046     B.UpdateVertex ( sae.FirstVertex(E1), bendtol1 );
3047     B.UpdateVertex ( sae.LastVertex(E1), bendtol1 );
3048     B.UpdateVertex ( sae.FirstVertex(E2), bendtol2 );
3049     B.UpdateVertex ( sae.LastVertex(E2), bendtol2 );
3050     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
3051     //:s3 abv 22 Apr 99: PRO7187 #11534: self-intersection not detected unitil curve is bent (!)
3052     FixSelfIntersectingEdge ( n1 );
3053     FixSelfIntersectingEdge ( n2 );
3054     FixIntersectingEdges ( n2 ); //skl 24.04.2003 for OCC58
3055 #ifdef OCCT_DEBUG
3056     cout << "Info: ShapeFix_Wire::FixLacking: Bending pcurves" << endl;
3057 #endif
3058     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
3059   }
3060   
3061   // increase vertex tolerance
3062   if ( doIncrease ) {
3063     B.UpdateVertex ( V1, 1.001 * inctol );
3064     B.UpdateVertex ( V2, 1.001 * inctol );
3065     myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
3066   }
3067
3068   if ( LastFixStatus ( ShapeExtend_DONE ) ) return Standard_True;
3069
3070   myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
3071   return Standard_False;
3072 }
3073
3074 //=======================================================================
3075 //function : FixNotchedEdges
3076 //purpose  : 
3077 //=======================================================================
3078
3079 Standard_Boolean ShapeFix_Wire::FixNotchedEdges()
3080 {
3081   myLastFixStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
3082   if ( ! IsReady() ) return Standard_False;
3083   
3084   Handle(ShapeAnalysis_Wire) theAdvAnalyzer = Handle(ShapeAnalysis_Wire)::DownCast(myAnalyzer);
3085   TopoDS_Face face = Face();
3086   if ( ! Context().IsNull() ) UpdateWire();
3087   Handle(ShapeExtend_WireData) sewd = WireData();
3088   
3089   for (Standard_Integer i = 1; i <= NbEdges() && NbEdges() > 2; i++) {
3090     Standard_Real param;
3091     Standard_Integer toRemove;
3092     if(theAdvAnalyzer->CheckNotchedEdges(i,toRemove,param,MinTolerance())){
3093       Standard_Integer n2 = (i > 0)  ? i : NbEdges();
3094       Standard_Integer n1 = (n2 > 1) ? n2-1 : NbEdges();
3095       Standard_Boolean isRemoveFirst = (n1==toRemove);
3096       Standard_Integer toSplit = (n2==toRemove ? n1 : n2);
3097       TopoDS_Edge splitE =  sewd->Edge ( toSplit );
3098       ShapeAnalysis_Edge sae;
3099       Handle(Geom2d_Curve) c2d;
3100       Standard_Real a, b;
3101       sae.PCurve ( splitE, face, c2d, a, b, Standard_True );
3102       Standard_Real ppar = (isRemoveFirst ? b : a);
3103       ShapeBuild_Edge sbe;
3104       TopAbs_Orientation orient = splitE.Orientation();
3105       if ( Abs(param - ppar) > ::Precision::PConfusion() ) {
3106         //pdn perform splitting of the edge and adding to wire
3107         
3108         //pdn check if it is necessary
3109         if( Abs((isRemoveFirst ? a : b)-param) < ::Precision::PConfusion() ) {
3110           continue;
3111         }
3112           
3113         Handle(ShapeAnalysis_TransferParametersProj) transferParameters =
3114           new ShapeAnalysis_TransferParametersProj;
3115         transferParameters->SetMaxTolerance(MaxTolerance());
3116         transferParameters->Init(splitE,face);
3117         Standard_Real first, last;
3118         if (a < b ) {
3119           first = a; 
3120           last = b;
3121         }
3122         else {
3123           first = b; 
3124           last = a;
3125         }
3126         TopoDS_Vertex Vnew;
3127         BRep_Builder B;
3128         B.MakeVertex(Vnew,Analyzer()->Surface()->Value(c2d->Value(param)),::Precision::Confusion());
3129         TopoDS_Edge wE = splitE;
3130         wE.Orientation ( TopAbs_FORWARD );
3131         TopoDS_Shape aTmpShape = Vnew.Oriented(TopAbs_REVERSED); //for porting
3132         TopoDS_Edge newE1 = sbe.CopyReplaceVertices ( wE, sae.FirstVertex(wE), TopoDS::Vertex(aTmpShape) );
3133         sbe.CopyPCurves ( newE1, wE  );
3134         transferParameters->TransferRange(newE1,first,param,Standard_True);
3135         B.SameRange(newE1,Standard_False);
3136         B.SameParameter(newE1,Standard_False);
3137         aTmpShape = Vnew.Oriented(TopAbs_FORWARD);
3138         TopoDS_Edge newE2 = sbe.CopyReplaceVertices ( wE, TopoDS::Vertex(aTmpShape),sae.LastVertex(wE) );
3139         sbe.CopyPCurves ( newE2, wE  );
3140         transferParameters->TransferRange(newE2,param,last,Standard_True);
3141         B.SameRange(newE2,Standard_False);
3142         B.SameParameter(newE2,Standard_False);
3143         
3144         if ( !Context().IsNull() ) {
3145           TopoDS_Wire wire;
3146           B.MakeWire(wire);
3147           B.Add(wire,newE1);
3148           B.Add(wire,newE2);
3149           Context()->Replace ( wE, wire );
3150         }
3151         
3152         newE1.Orientation(orient);
3153         newE2.Orientation(orient);
3154         if (orient==TopAbs_REVERSED){ TopoDS_Edge tmp = newE2; newE2 = newE1; newE1=tmp;}
3155         
3156         Standard_Boolean isRemoveLast = ((n1==NbEdges())&&(n2==1));
3157         sewd->Set ( newE1, toSplit);
3158         sewd->Add ( newE2, (toSplit==NbEdges()  ? 0 : toSplit+1));
3159         
3160         FixDummySeam(isRemoveLast ? NbEdges() : toRemove);
3161         myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
3162       }
3163       else 
3164       {
3165         FixDummySeam(n1);
3166         // The seam edge is removed from the list. So, need to step back to avoid missing of edge processing
3167         i--;
3168       }
3169   
3170       i--;
3171       if(!Context().IsNull()) //skl 07.03.2002 for OCC180
3172         UpdateWire();
3173       myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
3174     }
3175   }
3176   myStatusNotches = myLastFixStatus;
3177   return LastFixStatus ( ShapeExtend_DONE );
3178 }
3179
3180 //=======================================================================
3181 //function : FixDummySeam
3182 //purpose  : 
3183 //=======================================================================
3184
3185 static void CopyReversePcurves(const TopoDS_Edge& toedge, 
3186                                const TopoDS_Edge& fromedge,
3187                                const Standard_Boolean reverse)
3188 {
3189   TopLoc_Location fromLoc = fromedge.Location();
3190   TopLoc_Location toLoc = toedge.Location();
3191   for (BRep_ListIteratorOfListOfCurveRepresentation fromitcr
3192        ((*((Handle(BRep_TEdge)*)&fromedge.TShape()))->ChangeCurves()); fromitcr.More(); fromitcr.Next()) {
3193     Handle(BRep_GCurve) fromGC = Handle(BRep_GCurve)::DownCast(fromitcr.Value());
3194     if ( fromGC.IsNull() ) continue;
3195     if ( fromGC->IsCurveOnSurface() ) {
3196       Handle(Geom_Surface) surface = fromGC->Surface();
3197       TopLoc_Location L = fromGC->Location();
3198       Standard_Boolean found = Standard_False;
3199       BRep_ListOfCurveRepresentation& tolist = (*((Handle(BRep_TEdge)*)&toedge.TShape()))->ChangeCurves();
3200       Handle(BRep_GCurve) toGC;
3201       for (BRep_ListIteratorOfListOfCurveRepresentation toitcr (tolist); toitcr.More() && !found; toitcr.Next()) {
3202         toGC = Handle(BRep_GCurve)::DownCast(toitcr.Value());
3203         if ( toGC.IsNull() || !toGC->IsCurveOnSurface() || 
3204             surface != toGC->Surface() || L != toGC->Location() ) continue;
3205         found = Standard_True;
3206         break;
3207       }
3208       if (!found) {
3209         Standard_Real fp = fromGC->First();
3210         Standard_Real lp = fromGC->Last();
3211         toGC = Handle(BRep_GCurve)::DownCast(fromGC->Copy());
3212         tolist.Append (toGC);
3213         Handle(Geom2d_Curve) pcurve = Handle(Geom2d_Curve)::DownCast( fromGC->PCurve()->Copy() );
3214         if (reverse) {
3215           fp = pcurve->ReversedParameter(fp);
3216           lp = pcurve->ReversedParameter(lp);
3217           pcurve->Reverse();
3218           Standard_Real tmp = fp;
3219           fp = lp;
3220           lp = tmp;
3221         }
3222         //bug OCC209 invalid location of pcurve in the edge after copying
3223         TopLoc_Location newLoc = (fromLoc*L).Predivided(toLoc);
3224         toGC->SetRange(fp,lp);  
3225         toGC->PCurve(pcurve);
3226         toGC->Location(newLoc);
3227         if ( fromGC->IsCurveOnClosedSurface() ) {
3228           pcurve = fromGC->PCurve2();
3229           toGC->PCurve2(Handle(Geom2d_Curve)::DownCast(pcurve->Copy()));
3230         }
3231       }
3232     }
3233   }
3234 }
3235
3236 //=======================================================================
3237 //function : HasNewPCurves
3238 //purpose  : 
3239 //=======================================================================
3240 //  Note:    This function temporarily not used, because adress to it in
3241 //           function FixDummySeam() (see below line 2472) not used too
3242 //
3243 //static Standard_Boolean HasNewPCurves(const TopoDS_Edge& toedge, 
3244 //                                    const TopoDS_Edge& fromedge)
3245 //     
3246 //{
3247 //  for (BRep_ListIteratorOfListOfCurveRepresentation fromitcr
3248 //       ((*((Handle(BRep_TEdge)*)&fromedge.TShape()))->ChangeCurves()); fromitcr.More(); fromitcr.Next()) {
3249 //    Handle(BRep_GCurve) fromGC = Handle(BRep_GCurve)::DownCast(fromitcr.Value());
3250 //    if ( fromGC.IsNull() ) continue;
3251 //    if ( fromGC->IsCurveOnSurface() ) {
3252 //      Handle(Geom_Surface) surface = fromGC->Surface();
3253 //      TopLoc_Location L = fromGC->Location();
3254 //      Standard_Boolean found = Standard_False;
3255 //      BRep_ListOfCurveRepresentation& tolist = (*((Handle(BRep_TEdge)*)&toedge.TShape()))->ChangeCurves();
3256 //      Handle(BRep_GCurve) toGC;
3257 //      for (BRep_ListIteratorOfListOfCurveRepresentation toitcr (tolist); toitcr.More() && !found; toitcr.Next()) {
3258 //      toGC = Handle(BRep_GCurve)::DownCast(toitcr.Value());
3259 //      if ( toGC.IsNull() || !toGC->IsCurveOnSurface() || 
3260 //          surface != toGC->Surface() || L != toGC->Location() )  continue;
3261 //      found = Standard_True;
3262 //      break;
3263 //      }
3264 //      if (!found) 
3265 //      return Standard_True;
3266 //    }
3267 //  }
3268 //  return Standard_False;
3269 //}
3270
3271 //=======================================================================
3272 //function : FixDummySeam
3273 //purpose  : 
3274 //=======================================================================
3275
3276 void ShapeFix_Wire::FixDummySeam(const Standard_Integer num)
3277 {
3278   ShapeAnalysis_Edge sae;
3279   ShapeBuild_Edge sbe;
3280   ShapeBuild_Vertex sbv;
3281   Standard_Integer num1 = (num == NbEdges()) ? 1 : num+1;
3282   Handle(ShapeExtend_WireData) sewd = WireData();
3283   TopoDS_Edge E1 = sewd->Edge(num), E2 = sewd->Edge(num1);
3284   TopoDS_Vertex V1 = sae.FirstVertex(E1), V2 = sae.LastVertex(E2);
3285   TopoDS_Vertex Vm = sbv.CombineVertex ( V1, V2, 1.0001 );
3286   
3287   //pnd defining if new pcurves exists
3288   //pdn Temporary not removed
3289 //  Standard_Boolean toRemove = !(HasNewPCurves(E1,E2)||HasNewPCurves(E2,E1));
3290   Standard_Boolean toRemove = Standard_False;
3291   
3292   //creating new edge with pcurves and new vertex
3293   TopoDS_Vertex Vs = sae.FirstVertex(E2);
3294   if ( Vs.IsSame ( V1 ) || Vs.IsSame ( V2 ) ) Vs = Vm;
3295   TopoDS_Edge newEdge = sbe.CopyReplaceVertices ( E2, Vs, Vm );
3296   CopyReversePcurves(newEdge,E1,E1.Orientation()==E2.Orientation());
3297   BRep_Builder B;
3298   B.SameRange(newEdge,Standard_False);
3299   B.SameParameter(newEdge,Standard_False);
3300
3301   if ( !Context().IsNull() ) {
3302     if (toRemove) {
3303       Context()->Remove ( E2 );
3304       Context()->Remove ( E1 );
3305     }
3306     else {
3307       Context()->Replace ( E2, newEdge );
3308       Context()->Replace ( E1, newEdge.Reversed());
3309     }
3310     Context()->Replace ( V1, Vm.Oriented(V1.Orientation()) );
3311     Context()->Replace ( V2, Vm.Oriented(V2.Orientation()) );
3312   }
3313  
3314   Standard_Integer next = ( num1 == NbEdges()) ? 1 : num1+1;
3315   Standard_Integer prev = ( num > 1) ? num-1 : NbEdges();
3316   TopoDS_Edge prevE = sewd->Edge(prev), nextE = sewd->Edge(next);
3317   
3318   TopoDS_Edge tmpE1=sbe.CopyReplaceVertices( prevE, TopoDS_Vertex(), Vm);
3319   sewd->Set ( tmpE1,prev );
3320   if ( !Context().IsNull() ) Context()->Replace ( prevE, tmpE1);
3321   
3322   tmpE1  =  sbe.CopyReplaceVertices ( nextE, Vm, TopoDS_Vertex());
3323   sewd->Set ( tmpE1,next );
3324   if ( !Context().IsNull() ) Context()->Replace ( nextE, tmpE1);
3325   
3326   //removing edges from wire
3327   Standard_Integer n1, n2;
3328   if ( num < num1 ) {
3329     n1 = num; n2 = num1;
3330   } else {
3331     n1 = num1; n2 = num;
3332   }
3333   sewd->Remove(n2);
3334   sewd->Remove(n1);
3335 }
3336
3337 //=======================================================================
3338 //function : UpdateWire
3339 //purpose  : 
3340 //=======================================================================
3341
3342 void ShapeFix_Wire::UpdateWire () 
3343 {
3344   Handle(ShapeExtend_WireData) sbwd = WireData();
3345   for ( Standard_Integer i=1; i <= sbwd->NbEdges(); i++ ) {
3346     TopoDS_Edge E = sbwd->Edge(i);
3347     TopoDS_Shape S = Context()->Apply ( E );
3348     if ( S == E ) continue;
3349     for ( TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next() )
3350       sbwd->Add ( exp.Current(), i++ );
3351     sbwd->Remove ( i-- );
3352   }
3353 }
3354
3355 //=======================================================================
3356 //function : FixTails
3357 //purpose  :
3358 //=======================================================================
3359 Standard_Boolean ShapeFix_Wire::FixTails()
3360 {
3361   if (myMaxTailWidth < 0 || !IsReady())
3362   {
3363     return Standard_False;
3364   }
3365
3366   myLastFixStatus = ShapeExtend::EncodeStatus(ShapeExtend_OK);
3367   if (!Context().IsNull())
3368   {
3369     UpdateWire();
3370   }
3371   Handle(ShapeExtend_WireData) aSEWD = WireData();
3372   Standard_Integer aECount = NbEdges(), aENs[] = {aECount, 1};
3373   Standard_Boolean aCheckAngle = Standard_True;
3374   while (aECount >= 2 && aENs[1] <= aECount)
3375   {
3376     const TopoDS_Edge aEs[] = {aSEWD->Edge(aENs[0]), aSEWD->Edge(aENs[1])};
3377     TopoDS_Edge aEParts[2][2];
3378     if (!myAnalyzer->CheckTail(aEs[0], aEs[1],
3379       aCheckAngle ? myMaxTailAngleSine : -1, myMaxTailWidth, MaxTolerance(),
3380       aEParts[0][0], aEParts[0][1], aEParts[1][0], aEParts[1][1]))
3381     {
3382       aENs[0] = aENs[1]++;
3383       aCheckAngle = Standard_True;
3384       continue;
3385     }
3386
3387     // Provide not less than 1 edge in the result wire.
3388     Standard_Integer aSplitCounts[] =
3389       {aEParts[0][1].IsNull() ? 0 : 1, aEParts[1][1].IsNull() ? 0 : 1};
3390     const Standard_Integer aRemoveCount =
3391       (aEParts[0][0].IsNull() ? 0 : 1) + (aEParts[1][0].IsNull() ? 0 : 1);
3392     if (aECount + aSplitCounts[0] + aSplitCounts[1] < 1 + aRemoveCount)
3393     {
3394       aENs[0] = aENs[1]++;
3395       aCheckAngle = Standard_True;
3396       continue;
3397     }
3398
3399     // Split the edges.
3400     for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
3401     {
3402       if (aSplitCounts[aEI] == 0)
3403       {
3404         continue;
3405       }
3406
3407       // Replace the edge by the wire of its parts in the shape.
3408       const TopoDS_Edge aE = aEs[aEI];
3409       if (!Context().IsNull())
3410       {
3411         TopoDS_Wire aEWire;
3412         BRep_Builder().MakeWire(aEWire);
3413         BRep_Builder().Add(aEWire, aEParts[aEI][0]);
3414         BRep_Builder().Add(aEWire, aEParts[aEI][1]);
3415         TopoDS_Edge aFE = TopoDS::Edge(aE.Oriented(TopAbs_FORWARD));
3416         Context()->Replace(aFE, aEWire);
3417       }
3418
3419       // Replace the edge by its parts in the edge wire.
3420       const TopAbs_Orientation aOrient = aE.Orientation();
3421       aEParts[aEI][0].Orientation(aOrient);
3422       aEParts[aEI][1].Orientation(aOrient);
3423       const Standard_Integer aFirstPI = (aOrient != TopAbs_REVERSED) ? 0 : 1;
3424       const Standard_Integer aAdd =
3425         (aEI == 0 || aENs[1] < aENs[0]) ? 0 : aSplitCounts[0];
3426       aSEWD->Set(aEParts[aEI][aFirstPI], aENs[aEI] + aAdd);
3427       aSEWD->Add(aEParts[aEI][1 - aFirstPI], aENs[aEI] + 1 + aAdd);
3428     }
3429
3430     // Remove the tail.
3431     if (aRemoveCount == 2)
3432     {
3433       aCheckAngle = Standard_True;
3434       FixDummySeam(aENs[0] + aSplitCounts[0] +
3435         ((aENs[0] < aENs[1]) ? 0 : aSplitCounts[1]));
3436       if (!Context().IsNull())
3437       {
3438         UpdateWire();
3439       }
3440       myLastFixStatus |= ShapeExtend::EncodeStatus(ShapeExtend_DONE);
3441
3442       if (aSplitCounts[0] + aSplitCounts[1] == 2)
3443       {
3444         aENs[0] = aENs[1]++;
3445         continue;
3446       }
3447
3448       if (aSplitCounts[0] == aSplitCounts[1])
3449       {
3450         aECount -= 2;
3451         if (aENs[1] >= 3)
3452         {
3453           --aENs[0];
3454           --aENs[1];
3455         }
3456         else
3457         {
3458           aENs[0] = aECount;
3459           aENs[1] = 1;
3460         }
3461         aCheckAngle = Standard_False;
3462       }
3463       else
3464       {
3465         --aECount;
3466         if (aSplitCounts[0] != 0)
3467         {
3468           aENs[0] = (aENs[0] <= aECount) ? aENs[0] : aECount;
3469         }
3470         else
3471         {
3472           if (aENs[1] >= 3)
3473           {
3474             --aENs[0];
3475             --aENs[1];
3476           }
3477           else
3478           {
3479             aENs[0] = aECount;
3480             aENs[1] = 1;
3481           }
3482         }
3483       }
3484     }
3485     else
3486     {
3487       aCheckAngle = Standard_False;
3488       --aECount;
3489       const Standard_Integer aRI = aEParts[0][0].IsNull() ? 1 : 0;
3490       if (aSplitCounts[aRI] != 0)
3491       {
3492         if (aRI == 0)
3493         {
3494           if (aENs[1] >= 3)
3495           {
3496             --aENs[0];
3497             --aENs[1];
3498           }
3499           else
3500           {
3501             aENs[0] = aECount;
3502             aENs[1] = 1;
3503           }
3504         }
3505         else
3506         {
3507           aENs[0] = (aENs[1] > 1) ? aENs[0] : aECount;
3508         }
3509       }
3510       aSEWD->Remove(aENs[aRI] + ((aRI != 0 || aSplitCounts[0] == 0) ? 0 : 1));
3511       if (!Context().IsNull())
3512       {
3513         Context()->Remove(aEs[aRI].Oriented(TopAbs_FORWARD));
3514         UpdateWire();
3515       }
3516       myLastFixStatus |= ShapeExtend::EncodeStatus(ShapeExtend_DONE);
3517     }
3518   }
3519   myStatusNotches = myLastFixStatus;
3520   return ShapeExtend::DecodeStatus(myLastFixStatus, ShapeExtend_DONE);
3521 }