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