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