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