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