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