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