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