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