0024922: ShapeAnalysis_Wire::CheckIntersectingEdges doesn't report an intersection...
[occt.git] / src / ShapeAnalysis / ShapeAnalysis_Wire.cxx
1 // Created on: 2000-01-20
2 // Created by: data exchange team
3 // Copyright (c) 2000-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 //:pdn 11.12.98: FixDegenerated improved
17 //:pdn 05.01.99: renaming method CheckLittle to CheckSmall
18 //:l0 abv 10.01.99: CATIA01 #1727: fix intersecting edges always if edge is lacking
19 //:n2 abv 22.01.99: ma-test5.igs: IGES read (pref3d): remove degen edge with no pcurve
20 //:o4 abv 17.02.99: r0301_db.stp #53082: adding parameter isClosed to CheckOrder
21 //    rln 03.03.99  S4135: using updated ShapeAnalysis_Surface for checking of singularities
22 //:p9 abv 11.03.99: PRO7226 #489490: fix :i9 moved to allow fixing a set of degenerated edges
23 //#77 rln 11.03.99: S4135: using singularity which has minimum gap between singular point and input 3D point
24 //#84 rln 18.03.99: inserting degenerated edge between ends of pcurves
25 //pdn 12.03.99 S4135 check degenerated applies minimal tolerance first.
26 //pdn 16.03.99 S4135 adding check of non adjacent edjes.
27 //#83 rln 19.03.99: processing segments in intersection as in BRepCheck
28 //%15 pdn 15.03.99  checking of small area wire added
29 //#2 smh 26.03.99  S4163 Zero divide
30 //#4 szv           S4163 optimizing
31 //:r6 abv 08.04.99: protect FixIE against working out of curve range
32 //:s1 abv 22.04.99: PRO7226 #489490: ensure fixing of degenerated edge
33 //#9 smh 14.12.99 BUC60615 Using tolerance of verteces during checking degenerated edge.
34
35 #include <ShapeAnalysis_Wire.ixx>
36
37 #include <Precision.hxx>
38
39 #include <Geom_Curve.hxx>
40 #include <Geom2d_Curve.hxx>
41 #include <GeomAdaptor_HSurface.hxx>
42 #include <Geom2dAdaptor_Curve.hxx>
43 #include <Geom2dInt_GInter.hxx>
44 #include <IntRes2d_Domain.hxx>
45 #include <IntRes2d_Transition.hxx>
46 #include <IntRes2d_IntersectionPoint.hxx>
47 #include <IntRes2d_IntersectionSegment.hxx>
48
49 #include <TopoDS_Edge.hxx>
50 #include <TopoDS_Vertex.hxx>
51 #include <BRep_Builder.hxx>
52 #include <BRep_Tool.hxx>
53 #include <BRepTools.hxx>
54
55 #include <ShapeExtend.hxx>
56 #include <ShapeAnalysis.hxx>
57 #include <ShapeAnalysis_Curve.hxx>
58 #include <ShapeAnalysis_Edge.hxx>
59
60 #include <TopoDS.hxx>
61 #include <Precision.hxx>
62 #include <TColgp_Array1OfPnt.hxx>
63 #include <TColStd_Array1OfReal.hxx>
64 #include <Bnd_Array1OfBox2d.hxx>
65 #include <BndLib_Add2dCurve.hxx>
66 #include <Bnd_Box2d.hxx>
67
68 //szvsh addition
69 #include <Geom2dAdaptor_HCurve.hxx>
70 #include <Adaptor3d_CurveOnSurface.hxx>
71 #include <TColgp_SequenceOfPnt.hxx>
72 #include <ShapeAnalysis_Surface.hxx>
73 #include <TopoDS_Wire.hxx>
74 #include <ShapeAnalysis.hxx>
75 #include <Geom_Plane.hxx>
76 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
77 #include <TopoDS_Iterator.hxx>
78 #include <TopTools_DataMapOfShapeListOfShape.hxx>
79 #include <TopTools_ListOfShape.hxx>
80 #include <TopTools_IndexedMapOfShape.hxx>
81 #include <TopTools_ListIteratorOfListOfShape.hxx>
82 #include <TopExp.hxx>
83
84 //=======================================================================
85 //function : ShapeAnalysis_Wire
86 //purpose  : 
87 //=======================================================================
88
89 ShapeAnalysis_Wire::ShapeAnalysis_Wire()
90 {
91   ClearStatuses();
92   myPrecision = ::Precision::Confusion();
93 }
94
95 //=======================================================================
96 //function : ShapeAnalysis_Wire
97 //purpose  : 
98 //=======================================================================
99
100 ShapeAnalysis_Wire::ShapeAnalysis_Wire (const TopoDS_Wire& wire,
101                                         const TopoDS_Face& face,
102                                         const Standard_Real precision)
103 {
104   Init (wire, face, precision);
105 }
106
107 //=======================================================================
108 //function : ShapeAnalysis_Wire
109 //purpose  : 
110 //=======================================================================
111
112 ShapeAnalysis_Wire::ShapeAnalysis_Wire (const Handle(ShapeExtend_WireData)& sbwd,
113                                         const TopoDS_Face& face,
114                                         const Standard_Real precision)
115 {
116   Init (sbwd, face, precision);
117 }
118
119 //=======================================================================
120 //function : Init
121 //purpose  : 
122 //=======================================================================
123
124 void ShapeAnalysis_Wire::Init (const TopoDS_Wire& wire,
125                                const TopoDS_Face& face, const Standard_Real precision) 
126 {
127   Init (new ShapeExtend_WireData (wire), face, precision);
128 }
129
130 //=======================================================================
131 //function : Init
132 //purpose  : 
133 //=======================================================================
134
135 void ShapeAnalysis_Wire::Init (const Handle(ShapeExtend_WireData)& sbwd,
136                                const TopoDS_Face& face, const Standard_Real precision) 
137 {
138   Load (sbwd);
139   SetFace (face);
140   SetPrecision (precision);
141 }
142
143 //=======================================================================
144 //function : Load
145 //purpose  : 
146 //=======================================================================
147
148 void ShapeAnalysis_Wire::Load (const TopoDS_Wire& wire) 
149 {
150   ClearStatuses();
151   myWire = new ShapeExtend_WireData (wire);
152 }
153
154 //=======================================================================
155 //function : Load
156 //purpose  : 
157 //=======================================================================
158
159 void ShapeAnalysis_Wire::Load (const Handle(ShapeExtend_WireData)& sbwd) 
160 {
161   ClearStatuses();
162   myWire = sbwd;
163 }
164
165 //=======================================================================
166 //function : SetFace
167 //purpose  : 
168 //=======================================================================
169
170 void ShapeAnalysis_Wire::SetFace(const TopoDS_Face& face) 
171 {
172   myFace = face;
173   if(!face.IsNull())
174     mySurf = new ShapeAnalysis_Surface ( BRep_Tool::Surface ( myFace ) );
175 }
176
177 //=======================================================================
178 //function : SetSurface
179 //purpose  : 
180 //=======================================================================
181
182 void ShapeAnalysis_Wire::SetSurface (const Handle(Geom_Surface)& surface) 
183 {
184   SetSurface ( surface, TopLoc_Location() );
185 }
186
187 //=======================================================================
188 //function : SetSurface
189 //purpose  : 
190 //=======================================================================
191
192 void ShapeAnalysis_Wire::SetSurface (const Handle(Geom_Surface)& surface,
193                                      const TopLoc_Location& location) 
194 {
195   BRep_Builder B;
196   TopoDS_Face face;
197   B.MakeFace ( face, surface, location, ::Precision::Confusion() );
198   SetFace ( face );
199 }
200
201 //=======================================================================
202 //function : SetPrecision
203 //purpose  : 
204 //=======================================================================
205
206  void ShapeAnalysis_Wire::SetPrecision(const Standard_Real precision) 
207 {
208   myPrecision = precision;
209 }
210
211 //=======================================================================
212 //function : ClearStatuses
213 //purpose  : 
214 //=======================================================================
215
216  void ShapeAnalysis_Wire::ClearStatuses()
217 {
218   myStatusOrder = myStatusConnected =
219     myStatusEdgeCurves = myStatusDegenerated =
220       myStatusClosed = myStatusLacking =
221         myStatusSelfIntersection = myStatusSmall =
222           myStatusGaps3d = myStatusGaps2d =
223             myStatusCurveGaps = myStatusLoop = myStatus = 0;
224
225   myMin3d = myMin2d = myMax3d = myMax2d = 0.;
226 }
227
228 //=======================================================================
229 //function : Perform
230 //purpose  : 
231 //=======================================================================
232
233  Standard_Boolean ShapeAnalysis_Wire::Perform() 
234 {
235   Standard_Boolean result = Standard_False;
236   result |= CheckOrder();
237   result |= CheckSmall();
238   result |= CheckConnected();
239   result |= CheckEdgeCurves();
240   result |= CheckDegenerated();
241   result |= CheckSelfIntersection();
242   result |= CheckLacking();
243   result |= CheckClosed();
244   return result;
245 }
246
247 //=======================================================================
248 //function : CheckOrder
249 //purpose  : 
250 //=======================================================================
251
252  Standard_Boolean ShapeAnalysis_Wire::CheckOrder (const Standard_Boolean isClosed,
253                                                   const Standard_Boolean mode3d) 
254 {
255   ShapeAnalysis_WireOrder sawo;
256   CheckOrder (sawo, isClosed, mode3d);
257   myStatusOrder = myStatus;
258   return StatusOrder (ShapeExtend_DONE);
259 }
260
261 //=======================================================================
262 //function : CheckSmall
263 //purpose  : 
264 //=======================================================================
265
266  Standard_Boolean ShapeAnalysis_Wire::CheckSmall(const Standard_Real precsmall) 
267 {
268   for (Standard_Integer i = 1; i <= myWire->NbEdges(); i++) {
269     CheckSmall (i, precsmall);
270     myStatusSmall |= myStatus;
271   }
272   return StatusSmall (ShapeExtend_DONE);
273 }
274
275 //=======================================================================
276 //function : CheckConnected
277 //purpose  : 
278 //=======================================================================
279
280  Standard_Boolean ShapeAnalysis_Wire::CheckConnected(const Standard_Real prec) 
281 {
282   for (Standard_Integer i = 1; i <= myWire->NbEdges(); i++) {
283     CheckConnected ( i, prec );
284     myStatusConnected |= myStatus;
285   }
286   return StatusConnected (ShapeExtend_DONE);
287 }
288
289 //=======================================================================
290 //function : CheckEdgeCurves
291 //purpose  : 
292 //=======================================================================
293
294  Standard_Boolean ShapeAnalysis_Wire::CheckEdgeCurves() 
295 {
296   myStatusEdgeCurves = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
297   if ( ! IsReady() ) return Standard_False;
298   
299   Standard_Integer i, nb = myWire->NbEdges();
300   ShapeAnalysis_Edge SAE;
301   
302   for (i = 1; i <= nb; i++) {
303     TopoDS_Edge E = myWire->Edge (i);
304
305     SAE.CheckCurve3dWithPCurve (E, myFace);
306     if (SAE.Status (ShapeExtend_DONE))
307       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
308     if (SAE.Status ( ShapeExtend_FAIL)) 
309       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
310
311     SAE.CheckVerticesWithPCurve (E, myFace);
312     if (SAE.Status (ShapeExtend_DONE))
313       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_DONE2);
314     if (SAE.Status ( ShapeExtend_FAIL)) 
315       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
316
317     SAE.CheckVerticesWithCurve3d (E);
318     if (SAE.Status (ShapeExtend_DONE))
319       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_DONE3);
320     if (SAE.Status ( ShapeExtend_FAIL)) 
321       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL3);
322
323     CheckSeam (i);
324     if (LastCheckStatus (ShapeExtend_DONE)) 
325       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_DONE4);
326     if (LastCheckStatus (ShapeExtend_FAIL)) 
327       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL4);
328
329     CheckGap3d (i);
330     if (LastCheckStatus (ShapeExtend_DONE)) 
331       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_DONE5);
332     if (LastCheckStatus (ShapeExtend_FAIL)) 
333       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL5);
334
335     CheckGap2d (i);
336     if (LastCheckStatus (ShapeExtend_DONE)) 
337       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_DONE6);
338     if (LastCheckStatus (ShapeExtend_FAIL)) 
339       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL6);
340
341     Standard_Real maxdev = 0.0;
342     SAE.CheckSameParameter (myWire->Edge (i), maxdev);
343     if (SAE.Status (ShapeExtend_DONE))
344       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_DONE7);
345     if (SAE.Status ( ShapeExtend_FAIL)) 
346       myStatusEdgeCurves |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL7);
347   }
348   return StatusEdgeCurves (ShapeExtend_DONE);
349 }
350
351 //=======================================================================
352 //function : CheckDegenerated
353 //purpose  : 
354 //=======================================================================
355
356  Standard_Boolean ShapeAnalysis_Wire::CheckDegenerated() 
357 {
358   for (Standard_Integer i = 1; i <= myWire->NbEdges(); i++) {
359     CheckDegenerated (i);
360     myStatusDegenerated |= myStatus;
361   }
362   return StatusDegenerated (ShapeExtend_DONE);
363 }
364
365 //=======================================================================
366 //function : CheckSelfIntersection
367 //purpose  : 
368 //=======================================================================
369
370  Standard_Boolean ShapeAnalysis_Wire::CheckSelfIntersection() 
371 {
372   myStatusSelfIntersection = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
373   if (!IsReady()) return Standard_False;
374   Standard_Integer i, nb = myWire->NbEdges();
375   for (i = 1; i <= nb; i++) {
376     CheckSelfIntersectingEdge (i);
377     if (LastCheckStatus (ShapeExtend_DONE))
378       myStatusSelfIntersection |= ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
379     if (LastCheckStatus (ShapeExtend_FAIL)) 
380       myStatusSelfIntersection |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
381
382     CheckIntersectingEdges (i);
383     if (LastCheckStatus (ShapeExtend_DONE))
384       myStatusSelfIntersection |= ShapeExtend::EncodeStatus (ShapeExtend_DONE2);
385     if (LastCheckStatus (ShapeExtend_FAIL)) 
386       myStatusSelfIntersection |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
387   }
388   
389   Bnd_Array1OfBox2d boxes(1,nb);
390   TopLoc_Location L;
391   const Handle(Geom_Surface)& S = BRep_Tool::Surface(Face(), L);
392   Handle(Geom2d_Curve) c2d;
393   Standard_Real cf,cl;
394   ShapeAnalysis_Edge sae;
395   Handle(ShapeExtend_WireData) sbwd = WireData();
396   for(i = 1; i <= nb; i++){
397     TopoDS_Edge E = sbwd->Edge (i);
398     if(sae.PCurve (E,S,L,c2d,cf,cl,Standard_False)) {
399       Bnd_Box2d box;
400       Geom2dAdaptor_Curve gac(c2d,cf,cl);
401       BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
402       boxes(i) = box;
403     }
404   }
405   
406   Standard_Boolean isFail = Standard_False, isDone = Standard_False;
407   for(Standard_Integer num1 = 1; num1 < nb-1; num1++) {
408     Standard_Integer fin = nb;
409     if (CheckClosed(Precision::Confusion()) && 1 == num1)
410       fin = nb-1;
411     for(Standard_Integer num2 = num1+2; num2 <= fin; num2++) 
412       if(!boxes(num1).IsOut(boxes(num2))){
413         CheckIntersectingEdges(num1, num2);
414         isFail |= LastCheckStatus ( ShapeExtend_FAIL1 );
415         isDone |= LastCheckStatus ( ShapeExtend_DONE1 );
416       }
417   }
418   if(isFail)
419     myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL3 );
420   if(isDone)
421     myStatusSelfIntersection |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
422   
423   return StatusSelfIntersection (ShapeExtend_DONE);
424 }
425
426 //=======================================================================
427 //function : CheckLacking
428 //purpose  : 
429 //=======================================================================
430
431  Standard_Boolean ShapeAnalysis_Wire::CheckLacking() 
432 {
433   if (!IsReady() || NbEdges() < 2) return Standard_False; 
434   for (Standard_Integer i = 1; i <= myWire->NbEdges(); i++) {
435     CheckLacking (i);
436     myStatusLacking |= myStatus;
437   }
438   return StatusLacking (ShapeExtend_DONE);
439 }
440
441 //=======================================================================
442 //function : CheckClosed
443 //purpose  : 
444 //=======================================================================
445
446  Standard_Boolean ShapeAnalysis_Wire::CheckClosed(const Standard_Real prec) 
447 {
448   myStatusClosed = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
449   if (!IsReady() || NbEdges() < 1) return Standard_False;
450   
451   CheckConnected (1, prec);
452   if ( LastCheckStatus ( ShapeExtend_DONE ) ) 
453     myStatusClosed |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
454   if ( LastCheckStatus ( ShapeExtend_FAIL ) ) 
455     myStatusClosed |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
456
457   CheckDegenerated ( 1 );
458   if ( LastCheckStatus ( ShapeExtend_DONE ) ) 
459     myStatusClosed |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
460   if ( LastCheckStatus ( ShapeExtend_FAIL ) ) 
461     myStatusClosed |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
462
463   return StatusClosed ( ShapeExtend_DONE );
464 }
465
466 //=======================================================================
467 //function : CheckGaps3d
468 //purpose  : 
469 //=======================================================================
470
471  Standard_Boolean ShapeAnalysis_Wire::CheckGaps3d ()
472 {
473   myStatusGaps3d = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
474   if (!IsLoaded() || NbEdges() < 1) return Standard_False; //gka IsLoaded
475   
476   Standard_Real dist, maxdist = 0.;
477   
478   for (Standard_Integer i = 1; i <= NbEdges(); i++) {
479     CheckGap3d(i);
480     myStatusGaps3d |= myStatus;
481     if (!LastCheckStatus(ShapeExtend_FAIL1)) {
482       dist = MinDistance3d();
483       if (maxdist<dist) maxdist = dist;
484     }
485   }
486   myMin3d = myMax3d = maxdist;
487
488   return StatusGaps3d ( ShapeExtend_DONE );
489 }
490
491 //=======================================================================
492 //function : CheckGaps2d
493 //purpose  : 
494 //=======================================================================
495
496  Standard_Boolean ShapeAnalysis_Wire::CheckGaps2d ()
497 {
498   myStatusGaps2d = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
499   if (!IsReady() || NbEdges() < 1) return Standard_False;
500   
501   Standard_Real dist, maxdist = 0.;
502
503   for (Standard_Integer i = 1; i <= NbEdges(); i++) {
504     CheckGap2d(i);
505     myStatusGaps2d |= myStatus;
506     if (!LastCheckStatus(ShapeExtend_FAIL1)) {
507       dist = MinDistance2d();
508       if (maxdist<dist) maxdist = dist;
509     }
510   }
511   myMin2d = myMax2d = maxdist;
512
513   return StatusGaps2d ( ShapeExtend_DONE );
514 }
515
516 //=======================================================================
517 //function : CheckCurveGaps
518 //purpose  : 
519 //=======================================================================
520
521  Standard_Boolean ShapeAnalysis_Wire::CheckCurveGaps ()
522 {
523   myStatusCurveGaps = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
524   if (!IsReady() || NbEdges() < 1) return Standard_False;
525   
526   Standard_Real dist, maxdist = 0.;
527
528   for (Standard_Integer i = 1; i <= NbEdges(); i++) {
529     CheckCurveGap(i);
530     myStatusCurveGaps |= myStatus;
531     if (!LastCheckStatus(ShapeExtend_FAIL1)) {
532       dist = MinDistance3d();
533       if (maxdist<dist) maxdist = dist;
534     }
535   }
536   myMin3d = myMax3d = maxdist;
537
538   return StatusCurveGaps ( ShapeExtend_DONE );
539 }
540
541 //=======================================================================
542 //function : CheckOrder
543 //purpose  : 
544 //=======================================================================
545
546 Standard_Boolean ShapeAnalysis_Wire::CheckOrder(ShapeAnalysis_WireOrder& sawo,
547                                                 const Standard_Boolean isClosed,
548                                                 const Standard_Boolean mode3d) 
549 {
550   if ( ! mode3d && myFace.IsNull() ) {
551     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2); 
552     return Standard_False;
553   }
554   
555   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
556   sawo.SetMode ( mode3d, ( mode3d ? myPrecision : ::Precision::PConfusion() ) );
557   Standard_Integer i, nb = myWire->NbEdges();
558   ShapeAnalysis_Edge EA;
559   for (i = 1; i <= nb; i ++) {
560     TopoDS_Edge E = myWire->Edge(i);
561     if ( mode3d ) {
562       TopoDS_Vertex V1 = EA.FirstVertex (E); 
563       TopoDS_Vertex V2 = EA.LastVertex  (E); 
564       if (V1.IsNull() || V2.IsNull())
565       {
566         myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
567         return Standard_False;
568       }
569       gp_Pnt p1 = BRep_Tool::Pnt (V1);
570       gp_Pnt p2 = BRep_Tool::Pnt (V2);
571       sawo.Add (p1.XYZ(),p2.XYZ());
572     }
573     else {
574       Standard_Real f,l;
575       Handle(Geom2d_Curve) c2d;
576       TopoDS_Shape tmpF = myFace.Oriented(TopAbs_FORWARD);
577       if ( ! EA.PCurve(E,TopoDS::Face(tmpF),c2d,f,l) ) {
578         myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
579         return Standard_False;
580       }
581       sawo.Add(c2d->Value(f).XY(),c2d->Value(l).XY());
582     }
583   }
584   sawo.Perform(isClosed);
585   Standard_Integer stat = sawo.Status();
586   switch (stat) {
587   case   0: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);    break;
588   case   1: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1); break;
589   case   2: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE2); break;
590   case  -1: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE3); break;
591   case  -2: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE4); break;
592   case   3: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE5); break;//only shifted
593   case -10: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1); break;
594   }
595   return LastCheckStatus (ShapeExtend_DONE);
596 }
597
598 //=======================================================================
599 //function : CheckConnected
600 //purpose  : 
601 //=======================================================================
602
603 Standard_Boolean ShapeAnalysis_Wire::CheckConnected (const Standard_Integer num,
604                                                      const Standard_Real prec) 
605 {
606   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
607   if ( ! IsLoaded() || NbEdges() < 1 ) return Standard_False;
608
609   Standard_Integer n2 = ( num >0 ? num  : NbEdges() );
610   Standard_Integer n1 = ( n2  >1 ? n2-1 : NbEdges() );
611 //  if (n1 == n2) return 0;
612
613   TopoDS_Edge E1 = WireData()->Edge ( n1 );
614   TopoDS_Edge E2 = WireData()->Edge ( n2 );
615   
616   ShapeAnalysis_Edge sae;
617   TopoDS_Vertex V1 = sae.LastVertex (E1);
618   TopoDS_Vertex V2 = sae.FirstVertex (E2);
619   if (V1.IsNull() || V2.IsNull())
620   {
621     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
622     return Standard_False;
623   }
624   if (V1.IsSame(V2)) return Standard_False;
625
626   gp_Pnt p1 = BRep_Tool::Pnt (V1);
627   gp_Pnt p2 = BRep_Tool::Pnt (V2);
628   myMin3d = p1.Distance(p2);
629   if ( myMin3d <= gp::Resolution() ) myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
630   else if ( myMin3d <= myPrecision ) myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_DONE2);
631   else if ( myMin3d <= prec )        myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_DONE3);
632   else {
633     // et en inversant la derniere edge ?
634     if ( n1 == n2 ) myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
635     else {
636       V2 = sae.LastVertex (E2);
637       p2 = BRep_Tool::Pnt (V2);
638       Standard_Real dist = p1.Distance(p2);
639       if ( dist > myPrecision ) myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
640       else {
641         myMin3d = dist;
642         myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
643       }
644     }
645     return Standard_False;
646   }
647   return Standard_True;
648 }
649
650 //=======================================================================
651 //function : CheckSmall
652 //purpose  : 
653 //=======================================================================
654
655 Standard_Boolean ShapeAnalysis_Wire::CheckSmall (const Standard_Integer num,
656                                                  const Standard_Real precsmall) 
657 {
658   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
659   if ( ! IsLoaded() || NbEdges() <= 1 ) return Standard_False;
660
661   //Standard_Integer n = ( num ? num : NbEdges() ); //szv#4:S4163:12Mar99 not needed
662   TopoDS_Edge E = myWire->Edge ( num ? num : NbEdges() );
663   ShapeAnalysis_Edge sae;
664
665   if ( BRep_Tool::Degenerated ( E ) ) {
666     //:n2 abv 22 Jan 99: ma-test5.igs -> IGES (brep) -> read (pref3d):
667     // degen edge with no pcurve should be removed
668     if ( ! myFace.IsNull() && sae.HasPCurve ( E, Face() ) ) return Standard_False;
669     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
670   }
671   
672   TopoDS_Vertex V1 = sae.FirstVertex (E);
673   TopoDS_Vertex V2 = sae.LastVertex (E);
674   gp_Pnt p1 = BRep_Tool::Pnt (V1);
675   gp_Pnt p2 = BRep_Tool::Pnt (V2);
676   Standard_Real dist = p1.Distance(p2);
677   Standard_Real prec = precsmall;//Min ( myPrecision, precsmall );
678   //Standard_Real prec = Min(BRep_Tool::Tolerance(V1),BRep_Tool::Tolerance(V2)); //skl
679   if (dist > prec) return Standard_False;  // pas nulle
680   
681   // La courbe 3D a present : est-elle FERMEE ou DE LONGUEUR NULLE ... ???
682   // Pour cela on prend le point milieu (y a-t-il mieux)
683   // Si pas de C3D, on essaie la C2D ...
684
685   gp_Pnt Pm;
686   Standard_Real cf,cl;
687   Handle(Geom_Curve) c3d;    
688   if ( sae.Curve3d (E,c3d,cf,cl,Standard_False) ) Pm = c3d->Value ( (cf+cl)/2. );
689   else {
690     Handle(Geom2d_Curve) c2d;
691     if ( ! myFace.IsNull() && sae.PCurve (E,myFace,c2d,cf,cl,Standard_False)) {
692       gp_Pnt2d p2m = c2d->Value ( (cf+cl)/2. );
693       Pm = mySurf->Value (p2m);
694     }
695     else {
696       myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
697       Pm = p1;
698 //:n2      return Standard_False;
699     }
700   }
701   if ( Pm.Distance(p1) > prec || Pm.Distance(p2) > prec ) return Standard_False;
702
703   myStatus |= ShapeExtend::EncodeStatus ( V1.IsSame(V2) ? ShapeExtend_DONE1 : ShapeExtend_DONE2 );
704   return Standard_True;
705 }
706
707 //=======================================================================
708 //function : CheckSeam
709 //purpose  : 
710 //=======================================================================
711
712  Standard_Boolean ShapeAnalysis_Wire::CheckSeam(const Standard_Integer num,
713                                                 Handle(Geom2d_Curve)& C1,
714                                                 Handle(Geom2d_Curve)& C2,
715                                                 Standard_Real& cf,
716                                                 Standard_Real& cl) 
717 {
718   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
719   if (!IsReady()) return Standard_False;
720   Standard_Integer n = num;    if (n == 0) n = NbEdges();
721   TopoDS_Edge E = myWire->Edge (n);
722   if ( ! ShapeAnalysis_Edge().IsSeam ( E, myFace ) ) return Standard_False;
723   // Extract the Two PCurves of the Seam 
724   TopoDS_Face ForwardFace = myFace; ForwardFace.Orientation (TopAbs_FORWARD);
725   //szv#4:S4163:12Mar99 SGI warns
726   TopoDS_Shape EF = E.Oriented(TopAbs_FORWARD);
727   TopoDS_Shape ER = E.Oriented(TopAbs_REVERSED);
728   C1 = BRep_Tool::CurveOnSurface(TopoDS::Edge(EF), ForwardFace, cf, cl);
729   C2 = BRep_Tool::CurveOnSurface(TopoDS::Edge(ER), ForwardFace, cf, cl);
730   if (C1.IsNull() || C2.IsNull()) return Standard_False;
731
732 //  SelectForward est destine a devenir un outil distinct
733
734   Standard_Integer theCurveIndice = ShapeAnalysis_Curve().SelectForwardSeam (C1,C2);
735   if ( theCurveIndice != 2 ) return Standard_False;
736
737   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
738   return Standard_True;
739 }
740
741 //=======================================================================
742 //function : CheckSeam
743 //purpose  : 
744 //=======================================================================
745
746   Standard_Boolean ShapeAnalysis_Wire::CheckSeam(const Standard_Integer num) 
747 {
748   Handle(Geom2d_Curve) C1, C2;
749   Standard_Real cf, cl;
750   return CheckSeam (num, C1, C2, cf, cl);
751 }
752
753 //=======================================================================
754 //function : CheckDegenerated
755 //purpose  : 
756 //=======================================================================
757
758 Standard_Boolean ShapeAnalysis_Wire::CheckDegenerated (const Standard_Integer num,
759                                                        gp_Pnt2d& p2d1, gp_Pnt2d& p2d2) 
760 {
761   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
762   if ( ! IsReady() || NbEdges() < 1 ) return Standard_False;
763
764   Standard_Integer n2 = (num > 0)? num : NbEdges();
765   Standard_Integer n1 = (n2 > 1)? n2-1 : NbEdges();
766   Standard_Integer n3 = (n2 < NbEdges())? n2+1 : 1;
767   TopoDS_Edge E1 = myWire->Edge ( n1 );
768   TopoDS_Edge E2 = myWire->Edge ( n2 );
769   TopoDS_Edge E3 = myWire->Edge ( n3 );
770   
771   ShapeAnalysis_Edge sae;
772   
773   // skip if edge is already marked as degenerated and has pcurve
774   if ( BRep_Tool::Degenerated ( E2 ) && sae.HasPCurve ( E2, Face() ) ) {
775     // skl 30.12.2004 for OCC7630 - we have to check pcurve
776     if( sae.HasPCurve(E1,Face()) && sae.HasPCurve(E3,Face()) ) {
777       Handle(Geom2d_Curve) c2d;
778       Standard_Real fp,lp;
779       sae.PCurve ( E2, myFace, c2d, fp, lp, Standard_True );
780       gp_Pnt2d p21 = c2d->Value(fp);
781       gp_Pnt2d p22 = c2d->Value(lp);
782       sae.PCurve ( E1, myFace, c2d, fp, lp, Standard_True );
783       gp_Pnt2d p12 = c2d->Value(lp);
784       sae.PCurve ( E3, myFace, c2d, fp, lp, Standard_True );
785       gp_Pnt2d p31 = c2d->Value(fp);
786       if( fabs(p12.Distance(p31)-p21.Distance(p22)) > 2*Precision::PConfusion() ) {
787         // pcurve is bad => we can remove this edge in ShapeFix
788         // if set needed status
789         myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
790       }
791     }
792     return Standard_False;
793   }
794   
795   //pdn allows to insert two sequences of degenerated edges (on separate bounds of surfaces)
796   if ( n1 != n2 && BRep_Tool::Degenerated ( E1 ) && 
797        ! sae.HasPCurve ( E1, Face() ) ) {
798     //:abv 13.05.02: OCC320 - fail (to remove edge) if two consequtive degenerated edges w/o pcurves
799     if ( BRep_Tool::Degenerated ( E2 ) )
800       myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
801     return Standard_False;
802   }
803 //:i8  if ( BRep_Tool::Degenerated ( E1 ) || 
804 //:i8       BRep_Tool::Degenerated ( E2 ) ) return Standard_False;  // deja OK
805   
806   TopoDS_Vertex Vp = sae.FirstVertex (E1); //:i9
807   TopoDS_Vertex V0 = sae.LastVertex  (E1);
808   TopoDS_Vertex V1 = sae.FirstVertex (E2);
809   TopoDS_Vertex V2 = sae.LastVertex  (E2);
810
811   if (Vp.IsNull() || V0.IsNull() || V1.IsNull() || V2.IsNull())
812     return Standard_False;
813
814   gp_Pnt pp = BRep_Tool::Pnt (Vp); //:i9
815   gp_Pnt p0 = BRep_Tool::Pnt (V0);
816   gp_Pnt p1 = BRep_Tool::Pnt (V1);
817   gp_Pnt p2 = BRep_Tool::Pnt (V2);
818   Standard_Real par1, par2;
819   Standard_Boolean lack = Standard_False;
820   Standard_Boolean dgnr = Standard_False;
821   //pdn 12.03.99 minimal value processing first
822   Standard_Real precFirst = Min(myPrecision,BRep_Tool::Tolerance(V1));
823   Standard_Real precFin   = Max(myPrecision,BRep_Tool::Tolerance(V1));
824   Standard_Real precVtx   = (myPrecision<BRep_Tool::Tolerance(V1) ? 2*precFin : precFin);
825   //  forward : si Edge <num> FWD/REV. Si LACK, toujours True
826   Standard_Boolean forward = ( E2.Orientation() == TopAbs_FORWARD );
827   //  FIX FEV 1998 : recompute singularity according precision
828
829   if (p1.Distance(p2) <= precFirst) { // edge DGNR
830     dgnr = mySurf->DegeneratedValues ( p1, precVtx, p2d1, p2d2, par1, par2, forward ); //smh#9
831     if ( dgnr ) { // abv 24 Feb 00: trj3_as1-ac-214.stp #6065: avoid making closed edge degenerated
832       Standard_Real a, b;
833       Handle(Geom_Curve) C3d = BRep_Tool::Curve ( E2, a, b );
834       if ( ! C3d.IsNull() ) {
835         gp_Pnt p = C3d->Value ( 0.5 * ( a + b ) );
836         if ( p.SquareDistance ( p1 ) > precVtx * precVtx ) dgnr = Standard_False;
837       }
838     }
839   }
840   if ( ! dgnr ) {
841     //:i9 abv 23 Sep 98: CTS20315-2 #63231: check that previous edge is not degenerated
842     if ( n1 != n2 && p1.Distance(pp) <= precFirst &&
843          mySurf->IsDegenerated ( pp, precFirst ) && 
844          ! BRep_Tool::Degenerated ( E1 ) ) return Standard_False;
845     //rln S4135 ShapeAnalysis_Surface new algorithms for singularities
846     //:45 by abv 16 Dec 97: BUC60035 2659: precision increased to vertex tolerance
847     //Standard_Real prec = Max ( myPrecision, BRep_Tool::Tolerance(V1) );
848     //:51 abv 22 Dec 97: recompute singularities if necessary
849     //rln S4135 if ( prec > myPrecision ) mySurf->ComputeSingularities ( 2 * prec ); //:51 //:74 abv 15 Jan 97: *2
850
851     if ( p0.Distance ( p1 ) <= precFin ) {// ou DGNR manquante ?
852       //rln S4135 singularity with precision = 2 * prec, but distance <= prec
853       //lack = mySurf->DegeneratedValues ( p1, prec, p2d1, p2d2, par1, par2, forward);
854       Standard_Real tmpPreci;
855       gp_Pnt tmpP3d;
856       Standard_Boolean tmpUIsoDeg;
857       //#77 rln S4135: using singularity which has minimum gap between singular point and input 3D point
858       Standard_Integer indMin = -1;
859       Standard_Real gapMin2 = RealLast();
860       for (Standard_Integer i = 1; i <= mySurf->NbSingularities (precVtx); i++) {
861         mySurf->Singularity (i, tmpPreci, tmpP3d, p2d1, p2d2, par1, par2, tmpUIsoDeg);
862         Standard_Real gap2 = p1.SquareDistance (tmpP3d);
863         if (gap2 <= precVtx * precVtx)
864           if (gapMin2 > gap2) {
865             gapMin2 = gap2;
866             indMin = i;
867           }
868       }
869       if (indMin >= 1) {
870         mySurf->Singularity (indMin, tmpPreci, tmpP3d, p2d1, p2d2, par1, par2, tmpUIsoDeg);
871         lack = Standard_True;
872       }
873     }
874
875     //rln S4135 if ( prec > myPrecision ) mySurf->ComputeSingularities ( myPrecision ); //:51
876   }
877
878   //  voila, on a soit dgnr soit lack
879   if ( ! lack && ! dgnr ) {
880     //:abv 29.08.01: if singularity not detected but edge is marked 
881     // as degenerated, report fail
882     if ( BRep_Tool::Degenerated ( E2 ) && ! sae.HasPCurve ( E2, Face() ) )
883       myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
884     return Standard_False;
885   }
886   
887   // OK, degenerated case detected; we will find its start and end in 2d
888   
889   if ( lack ) forward = Standard_True;
890
891   //:24 by abv 28 Nov 97: 
892   // make degenerative pcurve parametrized exactly from end of pcurve of the 
893   // previous edge to the start of the next one
894   if ( lack || n1 != n2 ) { //:i8 abv 18 Sep 98: ProSTEP TR9 r0501-ug.stp #182180: single degedge is a wire at apex of a cone
895     Standard_Real a, b;
896     Handle(Geom2d_Curve) c2d;
897     if ( sae.PCurve ( E1, myFace, c2d, a, b, Standard_True ) ) {
898       p2d1 = c2d->Value ( b );
899       //#84 rln gp_Pnt2d p2d = c2d->Value ( b );
900       //#84 rln par1 = ( p2d.XY() - aP2d.XY() ) * theDir2d.XY();
901     }
902     else myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
903     //pdn pcurves (fixing regression in f0 in degenerated case) 
904     if ( sae.PCurve ( ( dgnr ? E3 : E2 ), myFace, c2d, a, b, Standard_True ) ) {
905       p2d2 = c2d->Value ( a );
906       //#84 rln gp_Pnt2d p2d = c2d->Value ( a );
907       //#84 rln par2 = ( p2d.XY() - aP2d.XY() ) * theDir2d.XY();
908     }
909     else myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
910   }
911 /*  
912   if ( par2 < par1 ) {
913     par1 = -par1;
914     par2 = -par2;
915     theDir2d.Reverse();
916   }
917 */
918   
919   //#84 rln 18.03.99 if pcurve is not degenerate anymore, the fix is postponned
920   //to ShapeFix_Wire::FixLacking
921   if ( ! mySurf->IsDegenerated ( p2d1, p2d2, precVtx, 10. ) ) { //:s1 abv 22 Apr 99: PRO7226 #489490 //smh#9
922     //:abv 24.05.02: OCC320 - fail (to remove edge) if two consequtive degenerated edges w/o pcurves
923     if ( BRep_Tool::Degenerated ( E2 ) )
924       myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
925     return Standard_False;
926   }
927
928   //added by rln 18/12/97 CSR# CTS18544 entity 13638
929   //the situation when degenerated edge already exists but flag is not set
930   //(i.e. the parametric space is closed)
931   GeomAdaptor_Surface& Ads = mySurf->Adaptor3d()->ChangeSurface();
932   Standard_Real max = Max ( Ads.UResolution(myPrecision), 
933                             Ads.VResolution(myPrecision) );
934   if ( p2d1.Distance (p2d2) /*Abs (par1 - par2)*/ <= max + gp::Resolution() ) return Standard_False;
935
936   //#84 rln p2d1 = aP2d.XY() + par1 * theDir2d.XY();
937   //#84 rln p2d2 = aP2d.XY() + par2 * theDir2d.XY();
938   myStatus = ShapeExtend::EncodeStatus ( dgnr ? ShapeExtend_DONE2 : ShapeExtend_DONE1 );
939   return Standard_True;
940 }
941
942 //=======================================================================
943 //function : CheckDegenerated
944 //purpose  : 
945 //=======================================================================
946
947 Standard_Boolean ShapeAnalysis_Wire::CheckDegenerated (const Standard_Integer num)
948 {
949   gp_Pnt2d p2d1, p2d2;
950   return CheckDegenerated ( num, p2d1, p2d2 );
951 }
952
953 //=======================================================================
954 //function : CheckGap3d
955 //purpose  : 
956 //=======================================================================
957
958  Standard_Boolean ShapeAnalysis_Wire::CheckGap3d(const Standard_Integer num) 
959 {
960   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
961   //szv#4:S4163:12Mar99 optimized
962   if ( !IsLoaded() || NbEdges() < 1 ) return Standard_False; //szvsh was nbedges < 2
963   Standard_Integer n2 = ( num >0 ? num  : NbEdges() );
964   Standard_Integer n1 = ( n2  >1 ? n2-1 : NbEdges() );
965   TopoDS_Edge E1 = myWire->Edge(n1);
966   TopoDS_Edge E2 = myWire->Edge(n2);
967   Standard_Real uf1,ul1,uf2,ul2;
968   Handle(Geom_Curve) C1,C2;
969   ShapeAnalysis_Edge SAE;
970   if (!SAE.Curve3d (E1,C1,uf1,ul1) || !SAE.Curve3d (E2,C2,uf2,ul2)) {
971     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
972     return Standard_False;
973   }
974   gp_Pnt p1 = C1->Value (ul1);
975   gp_Pnt p2 = C2->Value (uf2);
976   myMin3d = myMax3d = p1.Distance (p2);
977   if (myMin3d > myPrecision)
978     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
979   return LastCheckStatus (ShapeExtend_DONE);
980 }
981
982 //=======================================================================
983 //function : CheckGap2d
984 //purpose  : 
985 //=======================================================================
986
987  Standard_Boolean ShapeAnalysis_Wire::CheckGap2d(const Standard_Integer num) 
988 {
989   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
990   //szv#4:S4163:12Mar99 optimized
991   if ( !IsReady() || NbEdges() < 1 ) return Standard_False; //szvsh was nbedges < 2
992   Standard_Integer n2 = ( num >0 ? num  : NbEdges() );
993   Standard_Integer n1 = ( n2  >1 ? n2-1 : NbEdges() );
994   TopoDS_Edge E1 = myWire->Edge(n1);
995   TopoDS_Edge E2 = myWire->Edge(n2);
996   Standard_Real uf1,ul1,uf2,ul2;
997   Handle(Geom2d_Curve) C1,C2;
998   ShapeAnalysis_Edge SAE;
999   if (!SAE.PCurve (E1,myFace,C1,uf1,ul1) || !SAE.PCurve (E2,myFace,C2,uf2,ul2)) {
1000     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
1001     return Standard_False;
1002   }
1003   gp_Pnt2d p1 = C1->Value (ul1);
1004   gp_Pnt2d p2 = C2->Value (uf2);
1005   myMin2d = myMax2d = p1.Distance (p2);
1006   GeomAdaptor_Surface& SA = mySurf->Adaptor3d()->ChangeSurface();
1007   if (myMin2d > (Max (SA.UResolution (myPrecision), SA.VResolution (myPrecision)) + Precision::PConfusion()))
1008     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
1009   return LastCheckStatus (ShapeExtend_DONE);
1010 }
1011
1012 //=======================================================================
1013 //function : CheckCurveGap
1014 //purpose  : 
1015 //=======================================================================
1016
1017  Standard_Boolean ShapeAnalysis_Wire::CheckCurveGap(const Standard_Integer num)
1018 {
1019   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
1020   if ( !IsLoaded() || NbEdges() < 1 ) return Standard_False;
1021   Standard_Integer n = ( num >0 ? num  : NbEdges() );
1022   TopoDS_Edge E = myWire->Edge(n);
1023   Standard_Real cuf,cul,pcuf,pcul;
1024   Handle(Geom_Curve) c;
1025   ShapeAnalysis_Edge SAE;
1026   if (!SAE.Curve3d (E,c,cuf,cul,Standard_False)) {
1027     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
1028     return Standard_False;
1029   }
1030   Handle(Geom2d_Curve) pc;
1031   if (!SAE.PCurve (E,myFace,pc,pcuf,pcul,Standard_False)) {
1032     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
1033     return Standard_False;
1034   }
1035   Handle(Geom2dAdaptor_HCurve) AC = new Geom2dAdaptor_HCurve(pc,pcuf,pcul);
1036   Handle(GeomAdaptor_HSurface) AS = new GeomAdaptor_HSurface(mySurf->Surface());
1037   Adaptor3d_CurveOnSurface ACS(AC,AS);
1038   gp_Pnt cpnt, pcpnt;
1039   Standard_Integer nbp = 45;
1040   Standard_Real dist, maxdist=0.;
1041   for (Standard_Integer i=0; i<nbp; i++) {
1042     cpnt = c->Value(cuf + i*(cul-cuf)/(nbp-1));
1043     pcpnt = ACS.Value(pcuf + i*(pcul-pcuf)/(nbp-1));
1044     dist = cpnt.SquareDistance(pcpnt);
1045     if (maxdist<dist) maxdist = dist;
1046   }
1047   myMin3d = myMax3d = Sqrt(maxdist);
1048   if (myMin3d > myPrecision)
1049     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
1050   return LastCheckStatus (ShapeExtend_DONE);
1051 }
1052
1053 //=======================================================================
1054 //function : CheckSelfIntersectingEdge
1055 //purpose  : 
1056 //=======================================================================
1057
1058 // auxiliary function
1059 //:h0 abv 29 May 98: PRO10105 1949: like in BRepCheck, point is to be taken 
1060 // from 3d curve (but only if edge is SameParameter)
1061 static gp_Pnt GetPointOnEdge ( const TopoDS_Edge &edge, 
1062                                const Handle(ShapeAnalysis_Surface) &surf,
1063                                const Handle(Geom2d_Curve) &Crv2d, 
1064                                const Standard_Real param )
1065 {
1066   if ( BRep_Tool::SameParameter ( edge ) ) {
1067     Standard_Real f,l;
1068     TopLoc_Location L;
1069     const Handle(Geom_Curve) ConS = BRep_Tool::Curve ( edge, L, f, l );
1070     if ( ! ConS.IsNull() )
1071       return ConS->Value ( param ).Transformed ( L.Transformation() );
1072   }
1073   return surf->Value ( Crv2d->Value ( param ) );
1074 }
1075
1076 //=======================================================================
1077 //function : CheckSelfIntersectingEdge
1078 //purpose  : 
1079 //=======================================================================
1080
1081 Standard_Boolean ShapeAnalysis_Wire::CheckSelfIntersectingEdge (const Standard_Integer num,
1082                                                                 IntRes2d_SequenceOfIntersectionPoint& points2d,
1083                                                                 TColgp_SequenceOfPnt& points3d) 
1084 {
1085   points2d.Clear();
1086   points3d.Clear();
1087   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
1088   if ( ! IsReady() ) return Standard_False;
1089
1090   TopoDS_Edge edge = WireData()->Edge ( num >0 ? num : NbEdges() );
1091   ShapeAnalysis_Edge sae;
1092
1093   Standard_Real a, b;
1094   Handle(Geom2d_Curve) Crv;
1095   if ( ! sae.PCurve ( edge, myFace, Crv, a, b, Standard_False ) ) {
1096     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
1097     return Standard_False;
1098   }
1099   if ( Abs ( a - b ) <= ::Precision::PConfusion() ) return Standard_False;
1100   
1101   Standard_Real tolint = 1.0e-10; 
1102   //szv#4:S4163:12Mar99 warning
1103   IntRes2d_Domain domain ( Crv->Value ( a ), a, tolint, Crv->Value ( b ), b, tolint );
1104   Geom2dAdaptor_Curve AC ( Crv );
1105   Geom2dInt_GInter Inter ( AC, domain, tolint, tolint );
1106
1107   if ( ! Inter.IsDone() ) return Standard_False;
1108
1109   TopoDS_Vertex V1 = sae.FirstVertex ( edge );
1110   TopoDS_Vertex V2 = sae.LastVertex ( edge );
1111   if ( V1.IsNull() || V2.IsNull() ) {
1112     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
1113     return Standard_False;
1114   }
1115   Standard_Real tol1 = BRep_Tool::Tolerance ( V1 );
1116   Standard_Real tol2 = BRep_Tool::Tolerance ( V2 );
1117
1118   gp_Pnt pnt1 = BRep_Tool::Pnt ( V1 );
1119   gp_Pnt pnt2 = BRep_Tool::Pnt ( V2 );
1120
1121   for ( Standard_Integer i=1; i <= Inter.NbPoints(); i++ ) {
1122     const IntRes2d_IntersectionPoint &IP = Inter.Point ( i );
1123     const IntRes2d_Transition &Tr1 = IP.TransitionOfFirst();
1124     const IntRes2d_Transition &Tr2 = IP.TransitionOfSecond();
1125     if ( Tr1.PositionOnCurve() != IntRes2d_Middle &&
1126          Tr2.PositionOnCurve() != IntRes2d_Middle ) continue;
1127     gp_Pnt pint = GetPointOnEdge ( edge, mySurf, Crv, IP.ParamOnFirst() );
1128     Standard_Real dist21 = pnt1.SquareDistance ( pint );
1129     Standard_Real dist22 = pnt2.SquareDistance ( pint );
1130     if ( dist21 > tol1 * tol1 && dist22 > tol2 * tol2 ) {
1131       points2d.Append ( IP );
1132       points3d.Append ( pint );
1133       myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
1134     }
1135   }
1136
1137   return LastCheckStatus ( ShapeExtend_DONE );
1138 }
1139
1140 //=======================================================================
1141 //function : CheckSelfIntersectingEdge
1142 //purpose  : 
1143 //=======================================================================
1144
1145 Standard_Boolean ShapeAnalysis_Wire::CheckSelfIntersectingEdge (const Standard_Integer num)
1146 {
1147   IntRes2d_SequenceOfIntersectionPoint points2d;
1148   TColgp_SequenceOfPnt points3d;
1149   return CheckSelfIntersectingEdge ( num, points2d, points3d );
1150 }
1151
1152 //=======================================================================
1153 //function : CheckIntersectingEdges
1154 //purpose  : Test if two consequent edges are intersecting 
1155 //           It is made in accordance with the following check in BRepCheck:
1156 //         - in BRepCheck_Wire::Orientation(), test for self-intersection
1157 //=======================================================================
1158
1159 Standard_Boolean ShapeAnalysis_Wire::CheckIntersectingEdges (const Standard_Integer num,
1160                                                              IntRes2d_SequenceOfIntersectionPoint& points2d,
1161                                                              TColgp_SequenceOfPnt& points3d,
1162                                                              TColStd_SequenceOfReal& errors)
1163 {
1164   points2d.Clear();
1165   points3d.Clear();
1166   errors.Clear();
1167   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
1168   if ( ! IsReady() || NbEdges() <2 ) return Standard_False;
1169   
1170   //szv#4:S4163:12Mar99 optimized
1171   Standard_Integer n2 = (num > 0)? num : NbEdges();
1172   Standard_Integer n1 = (n2 > 1)? n2-1 : NbEdges();
1173   TopoDS_Edge edge1 = myWire->Edge ( n1 );
1174   TopoDS_Edge edge2 = myWire->Edge ( n2 );
1175
1176   ShapeAnalysis_Edge sae;
1177   TopoDS_Vertex V1 = sae.LastVertex ( edge1 );
1178   TopoDS_Vertex V2 = sae.FirstVertex ( edge2 );
1179   if ( V1.IsNull() || V2.IsNull() ) {
1180     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
1181     return Standard_False;
1182   }
1183   if ( ! BRepTools::Compare ( V1, V2 ) ) {
1184     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
1185     return Standard_False;
1186   }
1187
1188   TopoDS_Vertex Vp = sae.FirstVertex ( edge1 );
1189   TopoDS_Vertex Vn = sae.LastVertex ( edge2 );
1190
1191   Standard_Real a1, b1, a2, b2;
1192   Handle(Geom2d_Curve) Crv1, Crv2;
1193   if ( ! sae.PCurve ( edge1, myFace, Crv1, a1, b1, Standard_False ) ) {
1194     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL3);
1195     return Standard_False;
1196   }
1197   if ( ! sae.PCurve ( edge2, myFace, Crv2, a2, b2, Standard_False ) ) {
1198     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL3);
1199     return Standard_False;
1200   }
1201   if ( Abs ( a1 - b1 ) <= ::Precision::PConfusion() ||
1202        Abs ( a2 - b2 ) <= ::Precision::PConfusion() ) return Standard_False; //:f7 abv 6 May 98: BUC50070 on #42276
1203
1204   Standard_Boolean isForward1 = ( edge1.Orientation() == TopAbs_FORWARD );
1205   Standard_Boolean isForward2 = ( edge2.Orientation() == TopAbs_FORWARD );
1206
1207   Standard_Real tol0 = Max ( BRep_Tool::Tolerance ( V1 ), BRep_Tool::Tolerance ( V2 ) );
1208   Standard_Real tol = tol0;
1209
1210   gp_Pnt pnt = BRep_Tool::Pnt ( V1 );
1211
1212 //  Standard_Boolean Status = Standard_False;
1213
1214   Standard_Real tolint = 1.0e-10; 
1215
1216   //szv#4:S4163:12Mar99 warning
1217   IntRes2d_Domain d1 ( Crv1->Value ( a1 ), a1, tolint, 
1218                        Crv1->Value ( b1 ), b1, tolint );
1219   IntRes2d_Domain d2 ( Crv2->Value ( a2 ), a2, tolint, 
1220                        Crv2->Value ( b2 ), b2, tolint );
1221   Geom2dAdaptor_Curve C1 ( Crv1 ), C2 ( Crv2 );
1222
1223   //:64 abv 25 Dec 97: Attention!
1224   // Since Intersection algorithm is not symmetrical, for consistency with BRepCheck 
1225   // edge with lower order number shoud be intersecting with edge with higher one
1226   // i.e., for intersection of last and first edges, they should go in reversed order
1227   // Example: entity #38285 from bug CSR #CTS17806
1228   // NOTE: Tr1 and Tr2 are not reordered because they are used in the same manner
1229   Geom2dInt_GInter Inter;
1230   if ( num ==1 ) Inter.Perform ( C2, d2, C1, d1, tolint, tolint );
1231   else           Inter.Perform ( C1, d1, C2, d2, tolint, tolint );
1232   if ( ! Inter.IsDone() ) return Standard_False;
1233
1234   //:86 abv 22 Jan 98: fix self-intersection even if tolerance of vertex is enough
1235   // to annihilate it. This is done to prevent wrong effects if vertex tolerance 
1236   // will be decreased (e.g., in FixLacking)
1237   Standard_Real tole = Max ( ( BRep_Tool::SameParameter ( edge1 ) ? 
1238                                BRep_Tool::Tolerance ( edge1 ) : tol0 ),
1239                              ( BRep_Tool::SameParameter ( edge2 ) ? 
1240                                BRep_Tool::Tolerance ( edge2 ) : tol0 ) );
1241   Standard_Real tolt = Min ( tol, Max ( tole, myPrecision ) );
1242   //Standard_Real prevRange1 = RealLast(), prevRange2 = RealLast(); //SK
1243   Standard_Integer isLacking = -1; //:l0 abv: CATIA01 #1727: protect against adding lacking
1244   //#83 rln 19.03.99 sim2.igs, entity 4292
1245   //processing also segments as in BRepCheck
1246   Standard_Integer NbPoints = Inter.NbPoints(), NbSegments = Inter.NbSegments();
1247   for ( Standard_Integer i=1; i <= NbPoints + NbSegments; i++ ) {
1248     IntRes2d_IntersectionPoint IP;
1249     IntRes2d_Transition Tr1, Tr2;
1250     if (i <= NbPoints)
1251       IP = Inter.Point ( i );
1252     else {
1253       const IntRes2d_IntersectionSegment &Seg = Inter.Segment ( i - NbPoints );
1254       if (!Seg.HasFirstPoint() || !Seg.HasLastPoint()) continue;
1255       IP = Seg.FirstPoint();
1256       Tr1 = IP.TransitionOfFirst();
1257       Tr2 = IP.TransitionOfSecond();
1258       if (Tr1.PositionOnCurve() == IntRes2d_Middle || Tr2.PositionOnCurve() == IntRes2d_Middle)
1259         IP = Seg.LastPoint();
1260     }
1261     Tr1 = IP.TransitionOfFirst();
1262     Tr2 = IP.TransitionOfSecond();      
1263
1264     if ( Tr1.PositionOnCurve() != IntRes2d_Middle &&
1265          Tr2.PositionOnCurve() != IntRes2d_Middle ) continue;
1266     Standard_Real param1, param2;
1267     param1 = ( num ==1 ? IP.ParamOnSecond() : IP.ParamOnFirst() ); 
1268     param2 = ( num ==1 ? IP.ParamOnFirst()  : IP.ParamOnSecond() );
1269     
1270     //:r6 abv 8 Apr 99: r_47-sd.stp #173850: protect against working out of curve range
1271     if ( a1-param1 > ::Precision::PConfusion() || 
1272          param1-b1 > ::Precision::PConfusion() || 
1273          a2-param2 > ::Precision::PConfusion() || 
1274          param2-b2 > ::Precision::PConfusion() ) continue;
1275
1276     //:82 abv 21 Jan 98: point of intersection on Crv1 and Crv2 is different
1277     gp_Pnt pi1 = GetPointOnEdge ( edge1, mySurf, Crv1, param1 ); //:h0: thesurf.Value ( Crv1->Value ( param1 ) );
1278     gp_Pnt pi2 = GetPointOnEdge ( edge2, mySurf, Crv2, param2 ); //:h0: thesurf.Value ( Crv2->Value ( param2 ) );
1279     gp_Pnt pint = 0.5 * ( pi1.XYZ() + pi2.XYZ() );
1280     Standard_Real di1 = pi1.SquareDistance ( pnt );
1281     Standard_Real di2 = pi2.SquareDistance ( pnt );
1282     Standard_Real dist2 = Max ( di1, di2 );
1283
1284     //rln 03/02/98: CSR#BUC50004 entity 56 (to avoid later inserting lacking edge)
1285     if ( isLacking <0 ) { //:l0
1286       gp_Pnt2d end1 = Crv1->Value ( isForward1 ? b1 : a1 );
1287       gp_Pnt2d end2 = Crv2->Value ( isForward2 ? a2 : b2 );
1288 //:l0      Standard_Real distab2 = mySurf->Value ( end1 ).SquareDistance ( mySurf->Value ( end2 ) );
1289       //:l0: test like in BRepCheck
1290       GeomAdaptor_Surface& Ads = mySurf->Adaptor3d()->ChangeSurface();
1291       Standard_Real tol2d = 2 * Max ( Ads.UResolution(tol), Ads.VResolution(tol) );
1292       isLacking = ( end1.SquareDistance(end2) >= tol2d * tol2d );
1293     }
1294       
1295     if ( ( dist2 > tolt * tolt || //:86: tol -> tolt
1296            isLacking ) && //:l0
1297 //:l0      distab2 > BRep_Tool::Tolerance ( edge1 ) + BRep_Tool::Tolerance ( edge2 ) ) && //rln
1298          ( ! BRepTools::Compare ( Vp, Vn ) ||                          //:63
1299            dist2 < pint.SquareDistance ( BRep_Tool::Pnt ( Vp ) ) ) ) { //:63
1300       points2d.Append ( IP );
1301       points3d.Append ( pint );
1302       errors.Append ( 0.5 * pi1.Distance ( pi2 ) );
1303       myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
1304     }
1305   }
1306
1307   return LastCheckStatus ( ShapeExtend_DONE );
1308 }
1309
1310 //=======================================================================
1311 //function : CheckIntersectingEdges
1312 //purpose  : 
1313 //=======================================================================
1314
1315 Standard_Boolean ShapeAnalysis_Wire::CheckIntersectingEdges (const Standard_Integer num)
1316 {
1317   IntRes2d_SequenceOfIntersectionPoint points2d;
1318   TColgp_SequenceOfPnt points3d;
1319   TColStd_SequenceOfReal errors;
1320   return CheckIntersectingEdges ( num, points2d, points3d, errors );
1321 }
1322
1323 //=======================================================================
1324 //function : CheckIntersectingEdges
1325 //purpose  : 
1326 //=======================================================================
1327
1328 Standard_Boolean ShapeAnalysis_Wire::CheckIntersectingEdges(const Standard_Integer num1,
1329                                                             const Standard_Integer num2,
1330                                                             IntRes2d_SequenceOfIntersectionPoint& points2d,
1331                                                             TColgp_SequenceOfPnt& points3d,
1332                                                             TColStd_SequenceOfReal& errors)
1333 {
1334   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
1335   if ( ! IsReady() ) return Standard_False;
1336   Handle(ShapeExtend_WireData) sbwd = WireData();
1337   Standard_Integer n2 = ( num2 >0 ? num2  : sbwd->NbEdges() );
1338   Standard_Integer n1 = ( num1 >0 ? num1  : sbwd->NbEdges() );
1339   
1340   TopoDS_Edge edge1 = sbwd->Edge ( n1 );
1341   TopoDS_Edge edge2 = sbwd->Edge ( n2 );
1342   
1343   ShapeAnalysis_Edge sae;
1344   Standard_Real a1, b1, a2, b2;
1345   Handle(Geom2d_Curve) Crv1, Crv2;
1346   if(!sae.PCurve ( edge1, myFace, Crv1, a1, b1, Standard_False )){
1347     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL3);
1348     return Standard_False;
1349   }
1350     
1351   if(!sae.PCurve ( edge2, myFace, Crv2, a2, b2, Standard_False )){
1352     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL3);
1353     return Standard_False;
1354   }
1355   
1356   if ( Abs ( a1 - b1 ) <= ::Precision::PConfusion() ||
1357        Abs ( a2 - b2 ) <= ::Precision::PConfusion() ) return Standard_False;
1358   
1359   points2d.Clear();
1360   points3d.Clear();
1361   errors.Clear();
1362   TColgp_Array1OfPnt vertexPoints(1,4);
1363   TColStd_Array1OfReal vertexTolers(1,4);
1364   vertexPoints(1) = BRep_Tool::Pnt(sae.FirstVertex(edge1));
1365   vertexTolers(1) = BRep_Tool::Tolerance(sae.FirstVertex(edge1));
1366   vertexPoints(2) = BRep_Tool::Pnt(sae.LastVertex(edge1));
1367   vertexTolers(2) = BRep_Tool::Tolerance(sae.LastVertex(edge1));
1368   vertexPoints(3) = BRep_Tool::Pnt(sae.FirstVertex(edge2));
1369   vertexTolers(3) = BRep_Tool::Tolerance(sae.FirstVertex(edge2));
1370   vertexPoints(4) = BRep_Tool::Pnt(sae.LastVertex(edge2));
1371   vertexTolers(4) = BRep_Tool::Tolerance(sae.LastVertex(edge2));
1372   
1373   Standard_Real tolint = 1.0e-10; 
1374
1375   IntRes2d_Domain d1 ( Crv1->Value ( a1 ), a1, tolint, 
1376                        Crv1->Value ( b1 ), b1, tolint );
1377   IntRes2d_Domain d2 ( Crv2->Value ( a2 ), a2, tolint, 
1378                        Crv2->Value ( b2 ), b2, tolint );
1379   Geom2dAdaptor_Curve C1 ( Crv1 ), C2 ( Crv2 );
1380   
1381   Geom2dInt_GInter Inter;
1382   Inter.Perform ( C1, d1, C2, d2, tolint, tolint );
1383   if ( ! Inter.IsDone() ) return Standard_False;
1384   
1385   //#83 rln 19.03.99 sim2.igs, entity 4292
1386   //processing also segments as in BRepCheck
1387   Standard_Integer NbPoints = Inter.NbPoints(), NbSegments = Inter.NbSegments();
1388   for ( Standard_Integer i=1; i <= NbPoints + NbSegments; i++ ) {
1389     IntRes2d_IntersectionPoint IP;
1390     IntRes2d_Transition Tr1, Tr2;
1391     if (i <= NbPoints)
1392       IP = Inter.Point ( i );
1393     else {
1394       const IntRes2d_IntersectionSegment &Seg = Inter.Segment ( i - NbPoints );
1395       if (!Seg.HasFirstPoint() || !Seg.HasLastPoint()) continue;
1396       IP = Seg.FirstPoint();
1397       Tr1 = IP.TransitionOfFirst();
1398       Tr2 = IP.TransitionOfSecond();
1399       if (Tr1.PositionOnCurve() == IntRes2d_Middle || Tr2.PositionOnCurve() == IntRes2d_Middle)
1400         IP = Seg.LastPoint();
1401     }
1402     Tr1 = IP.TransitionOfFirst();
1403     Tr2 = IP.TransitionOfSecond();      
1404     if ( Tr1.PositionOnCurve() != IntRes2d_Middle &&
1405          Tr2.PositionOnCurve() != IntRes2d_Middle ) continue;
1406     Standard_Real param1 = IP.ParamOnFirst(); 
1407     Standard_Real param2 = IP.ParamOnSecond();
1408     gp_Pnt pi1 = GetPointOnEdge ( edge1, mySurf, Crv1, param1 ); //:h0: thesurf.Value ( Crv1->Value ( param1 ) );
1409     gp_Pnt pi2 = GetPointOnEdge ( edge2, mySurf, Crv2, param2 );
1410     Standard_Boolean OK1 = Standard_False;
1411     Standard_Boolean OK2 = Standard_False;
1412
1413     for(Standard_Integer j=1; (j<=2)&&!OK1; j++) {
1414       Standard_Real di1 = pi1.SquareDistance (vertexPoints(j));
1415       if(di1 < vertexTolers(j) * vertexTolers(j))
1416         OK1 = Standard_True;
1417     }
1418
1419     for(Standard_Integer j=3; (j<=4)&&!OK2; j++) {
1420       Standard_Real di2 = pi2.SquareDistance (vertexPoints(j));
1421       if(di2 < vertexTolers(j) * vertexTolers(j))
1422         OK2 = Standard_True;
1423     }
1424
1425     if(!OK1 || !OK2) {
1426       gp_Pnt pint = 0.5 * ( pi1.XYZ() + pi2.XYZ() );
1427       points2d.Append ( IP );
1428       points3d.Append ( pint );
1429       errors.Append ( 0.5 * pi1.Distance ( pi2 ) );
1430       myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_DONE1);   
1431     }
1432   }
1433   return LastCheckStatus ( ShapeExtend_DONE );
1434 }
1435
1436 //=======================================================================
1437 //function : CheckIntersectingEdges
1438 //purpose  : 
1439 //=======================================================================
1440
1441 Standard_Boolean ShapeAnalysis_Wire::CheckIntersectingEdges (const Standard_Integer num1,
1442                                                              const Standard_Integer num2)
1443 {
1444   IntRes2d_SequenceOfIntersectionPoint points2d;
1445   TColgp_SequenceOfPnt points3d;
1446   TColStd_SequenceOfReal errors;
1447   return CheckIntersectingEdges(num1, num2, points2d, points3d, errors);
1448 }
1449
1450 //=======================================================================
1451 //function : CheckLacking
1452 //purpose  : Test if two edges are disconnected in 2d according to the 
1453 //           Adaptor_Surface::Resolution
1454 //=======================================================================
1455
1456 Standard_Boolean ShapeAnalysis_Wire::CheckLacking (const Standard_Integer num,
1457                                                    const Standard_Real Tolerance,
1458                                                    gp_Pnt2d &p2d1, gp_Pnt2d &p2d2) 
1459 {
1460   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
1461   if ( ! IsReady() ) return Standard_False;
1462   
1463   //szv#4:S4163:12Mar99 optimized
1464   Standard_Integer n2 = (num > 0)? num : NbEdges();
1465   Standard_Integer n1 = (n2 > 1)? n2-1 : NbEdges();
1466   TopoDS_Edge E1 = myWire->Edge ( n1 );
1467   TopoDS_Edge E2 = myWire->Edge ( n2 );
1468   
1469   ShapeAnalysis_Edge sae;
1470   TopoDS_Vertex V1 = sae.LastVertex ( E1 );
1471   TopoDS_Vertex V2 = sae.FirstVertex ( E2 );
1472   // CKY 4 MAR 1998 : protection against null vertex
1473   if ( V1.IsNull() || V2.IsNull() ) {
1474     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
1475     return Standard_False;
1476   }
1477   if ( ! BRepTools::Compare ( V1, V2 ) ) {
1478     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
1479     return Standard_False;
1480   }
1481
1482   Standard_Real a, b;
1483   gp_Vec2d v1, v2, v12;
1484   Handle(Geom2d_Curve) c2d;
1485   if ( ! sae.PCurve ( E1, myFace, c2d, a, b, Standard_True ) ) {
1486     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL3);
1487     return Standard_False;
1488   }
1489   c2d->D1 ( b, p2d1, v1 ); 
1490   if ( E1.Orientation() == TopAbs_REVERSED ) v1.Reverse();
1491   if ( ! sae.PCurve ( E2, myFace, c2d, a, b, Standard_True ) ) {
1492     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL3);
1493     return Standard_False;
1494   }
1495   c2d->D1 ( a, p2d2, v2 );
1496   if ( E2.Orientation() == TopAbs_REVERSED ) v2.Reverse();
1497   v12 = p2d2.XY() - p2d1.XY();
1498   myMax2d = v12.SquareMagnitude();
1499
1500   // test like in BRepCheck
1501   Standard_Real tol = Max ( BRep_Tool::Tolerance ( V1 ), BRep_Tool::Tolerance ( V2 ) );
1502   tol = ( Tolerance > gp::Resolution() && Tolerance < tol ? Tolerance : tol );
1503   GeomAdaptor_Surface& Ads = mySurf->Adaptor3d()->ChangeSurface();
1504   Standard_Real tol2d = 2 * Max ( Ads.UResolution(tol), Ads.VResolution(tol) );
1505   if ( // tol2d < gp::Resolution() || //#2 smh 26.03.99 S4163 Zero divide
1506        myMax2d < tol2d * tol2d ) return Standard_False;
1507
1508   myMax2d = Sqrt ( myMax2d );
1509   myMax3d = tol * myMax2d / Max ( tol2d, gp::Resolution() );
1510   myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
1511
1512   if ( myMax2d < Precision::PConfusion() || //:abv 03.06.02 CTS21866.stp
1513        ( v1.SquareMagnitude() > gp::Resolution() && Abs ( v12.Angle ( v1 ) ) > 0.9 * M_PI ) ||
1514        ( v2.SquareMagnitude() > gp::Resolution() && Abs ( v12.Angle ( v2 ) ) > 0.9 * M_PI ) ) 
1515        myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
1516   return Standard_True;
1517 }
1518
1519 //=======================================================================
1520 //function : CheckLacking
1521 //purpose  :
1522 //          
1523 //=======================================================================
1524
1525 Standard_Boolean ShapeAnalysis_Wire::CheckLacking (const Standard_Integer num,
1526                                                    const Standard_Real Tolerance)
1527 {
1528   gp_Pnt2d p1, p2;
1529   return CheckLacking (num, Tolerance, p1, p2);
1530 }
1531
1532 //=======================================================================
1533 //function : CheckOuterBound
1534 //purpose  : 
1535 //=======================================================================
1536
1537  Standard_Boolean ShapeAnalysis_Wire::CheckOuterBound(const Standard_Boolean APIMake)
1538 {
1539   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
1540   if ( ! IsReady() ) return Standard_False;
1541
1542   TopoDS_Wire wire;
1543   if (APIMake) wire = myWire->WireAPIMake();
1544   else         wire = myWire->Wire();
1545   
1546   TopoDS_Shape sh = myFace.EmptyCopied(); //szv#4:S4163:12Mar99 SGI warns
1547   TopoDS_Face face = TopoDS::Face(sh);
1548   BRep_Builder B;
1549   B.Add (face, wire);
1550   if (ShapeAnalysis::IsOuterBound (face)) return Standard_False;
1551   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
1552   return Standard_True;
1553 }
1554
1555 //=======================================================================
1556 //function : CheckNotchedEdges
1557 //purpose  : 
1558 //=======================================================================
1559
1560 static Standard_Real ProjectInside(const Adaptor3d_CurveOnSurface AD,
1561                                    const gp_Pnt pnt,
1562                                    const Standard_Real preci,
1563                                    gp_Pnt& proj,
1564                                    Standard_Real& param,
1565                                    const Standard_Boolean adjustToEnds = Standard_True)
1566 {
1567   ShapeAnalysis_Curve sac;
1568   Standard_Real dist = sac.Project(AD,pnt,preci,proj,param,adjustToEnds);
1569   Standard_Real uFirst = AD.FirstParameter();
1570   Standard_Real uLast = AD.LastParameter();
1571   if(param<uFirst) {
1572     param = uFirst;
1573     proj = AD.Value(uFirst);
1574     return proj.Distance(pnt);
1575   }
1576   
1577   if(param>uLast) {
1578     param = uLast;
1579     proj = AD.Value(uLast);
1580     return proj.Distance(pnt);
1581   }
1582   return dist;
1583 }
1584   
1585 Standard_Boolean ShapeAnalysis_Wire::CheckNotchedEdges(const Standard_Integer num,
1586                                                        Standard_Integer& shortNum,
1587                                                        Standard_Real& param,
1588                                                        const Standard_Real Tolerance)
1589 {
1590   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
1591   if ( ! IsReady() ) return Standard_False;
1592   
1593   Standard_Integer n2 = (num > 0)? num : NbEdges();
1594   Standard_Integer n1 = (n2 > 1)? n2-1 : NbEdges();
1595   TopoDS_Edge E1 = myWire->Edge ( n1 );
1596   TopoDS_Edge E2 = myWire->Edge ( n2 );
1597   
1598   if(BRep_Tool::Degenerated(E1)||BRep_Tool::Degenerated(E2))
1599     return Standard_False;
1600   
1601   ShapeAnalysis_Edge sae;
1602   TopoDS_Vertex V1 = sae.LastVertex ( E1 );
1603   TopoDS_Vertex V2 = sae.FirstVertex ( E2 );
1604   
1605   if ( V1.IsNull() || V2.IsNull() ) {
1606     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
1607     return Standard_False;
1608   }
1609   if ( ! BRepTools::Compare ( V1, V2 ) ) {
1610     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
1611     return Standard_False;
1612   }
1613
1614   Standard_Real a1, b1, a2, b2;
1615   gp_Pnt2d p2d1, p2d2;
1616   gp_Vec2d v1, v2;
1617   Handle(Geom2d_Curve) c2d1, c2d2;
1618   if ( ! sae.PCurve ( E1, myFace, c2d1, a1, b1, Standard_False ) ) {
1619     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL3);
1620     return Standard_False;
1621   }
1622   
1623   if(E1.Orientation()==TopAbs_REVERSED)
1624     c2d1->D1 ( a1, p2d1, v1 );
1625   else {
1626     c2d1->D1 ( b1, p2d1, v1 );
1627     v1.Reverse();
1628   }
1629   
1630   if ( ! sae.PCurve ( E2, myFace, c2d2, a2, b2, Standard_False ) ) {
1631     myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_FAIL3);
1632     return Standard_False;
1633   }
1634   if(E2.Orientation()==TopAbs_REVERSED) {
1635     c2d2->D1 ( b2, p2d2, v2 );
1636     v2.Reverse();
1637   }
1638   else 
1639     c2d2->D1 ( a2, p2d2, v2 );
1640   
1641   if ( v2.Magnitude() < gp::Resolution() || v1.Magnitude() < gp::Resolution())
1642     return Standard_False;
1643   
1644   if ( Abs ( v2.Angle ( v1 ) ) > 0.1 || p2d1.Distance(p2d2) > Tolerance)
1645     return Standard_False;
1646   
1647   Handle(Geom2dAdaptor_HCurve) AC2d1  = new Geom2dAdaptor_HCurve(c2d1,a1,b1);
1648   Handle(GeomAdaptor_HSurface) AdS1 = new GeomAdaptor_HSurface(new Geom_Plane(gp_Pln()));
1649   Adaptor3d_CurveOnSurface Ad1(AC2d1,AdS1);
1650   
1651   Handle(Geom2dAdaptor_HCurve) AC2d2  = new Geom2dAdaptor_HCurve(c2d2,a2,b2);
1652   Handle(GeomAdaptor_HSurface) AdS2 = new GeomAdaptor_HSurface(new Geom_Plane(gp_Pln()));
1653   Adaptor3d_CurveOnSurface Ad2(AC2d2,AdS2);
1654   
1655   Adaptor3d_CurveOnSurface longAD, shortAD;
1656   Standard_Real lenP, firstP;
1657   
1658   ShapeAnalysis_Curve sac;
1659   
1660   gp_Pnt Proj1, Proj2;
1661   Standard_Real param1 = 0., param2 = 0.;
1662   p2d2=c2d2->Value(E2.Orientation()==TopAbs_FORWARD ? b2 : a2);
1663   p2d1=c2d1->Value(E1.Orientation()==TopAbs_FORWARD ? a1 : b1);
1664   Standard_Real dist1 = ProjectInside(Ad1,gp_Pnt(p2d2.X(),p2d2.Y(),0),Tolerance,Proj1,param1,Standard_False);
1665   Standard_Real dist2 = ProjectInside(Ad2,gp_Pnt(p2d1.X(),p2d1.Y(),0),Tolerance,Proj2,param2,Standard_False);
1666   
1667   if ( dist1 > Tolerance && dist2 > Tolerance)
1668     return Standard_False;
1669   
1670   if (dist1 < dist2 ) {
1671     shortAD = Ad2;
1672     longAD = Ad1;
1673     lenP = b2 - a2;
1674     firstP = a2;
1675     shortNum=n2;
1676     param=param1;
1677     
1678   }
1679   else {
1680     shortAD = Ad1;
1681     longAD = Ad2;
1682     lenP = b1 - a1;
1683     firstP = a1;
1684     shortNum=n1;
1685     param=param2;
1686   }
1687   
1688   Standard_Real step = lenP/23;
1689   for (Standard_Integer i = 1; i < 23; i++,firstP+=step) {
1690     Standard_Real d1 = sac.Project(longAD,shortAD.Value(firstP),Tolerance,Proj1,param1);
1691     if (d1 > Tolerance) {
1692       return Standard_False;
1693     }
1694   }
1695   
1696   return Standard_True; 
1697 }
1698
1699 //=======================================================================
1700 //function : CheckSmallArea
1701 //purpose  : 
1702 //=======================================================================
1703
1704 Standard_Boolean ShapeAnalysis_Wire::CheckSmallArea(const Standard_Real prec2d)
1705 {
1706   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
1707   Standard_Integer NbEdges = myWire->NbEdges();
1708   if ( !IsReady() || NbEdges <1 ) return Standard_False;
1709   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
1710   
1711   Standard_Integer NbControl=23;
1712   Standard_Real area=0;
1713   gp_XY prev, cont;
1714   for (Standard_Integer nbe = 1; nbe <= NbEdges; nbe++) {
1715     Standard_Real First, Last;
1716     Handle(Geom2d_Curve) c2d;
1717     ShapeAnalysis_Edge sae;
1718     if (!sae.PCurve(myWire->Edge(nbe),myFace,c2d,First,Last)) {
1719       myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
1720       return Standard_False;
1721     }
1722     
1723     Standard_Integer ibeg = 0;
1724     if( nbe == 1 ) {
1725       gp_Pnt2d pntIni = c2d->Value(First);
1726       prev = pntIni.XY();
1727       cont = prev;
1728       ibeg = 1;
1729     }
1730     for ( Standard_Integer i = ibeg; i < NbControl; i++) {
1731       Standard_Real prm = ((NbControl-1-i)*First + i*Last)/(NbControl-1);
1732       gp_Pnt2d pntCurr = c2d->Value(prm);
1733       gp_XY curr = pntCurr.XY();
1734       area += curr ^ prev;
1735       prev = curr;
1736     }
1737   }
1738   area +=  cont ^ prev;
1739   if ( Abs(area) < 2*prec2d*prec2d ) {
1740     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
1741     return Standard_True;
1742   }
1743   return Standard_False;
1744 }
1745
1746 //=======================================================================
1747 //function : CheckShapeConnect
1748 //purpose  : 
1749 //=======================================================================
1750
1751  Standard_Boolean ShapeAnalysis_Wire::CheckShapeConnect(const TopoDS_Shape& shape,const Standard_Real prec) 
1752 {
1753   Standard_Real tailhead, tailtail, headhead, headtail;
1754   return CheckShapeConnect (tailhead, tailtail, headtail, headhead, shape, prec);
1755 }
1756
1757 //=======================================================================
1758 //function : CheckShapeConnect
1759 //purpose  : 
1760 //=======================================================================
1761
1762  Standard_Boolean ShapeAnalysis_Wire::CheckShapeConnect(Standard_Real& tailhead, Standard_Real& tailtail,
1763                                                         Standard_Real& headtail, Standard_Real& headhead,
1764                                                         const TopoDS_Shape& shape, const Standard_Real prec) 
1765 {
1766     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
1767   if (!IsLoaded () || shape.IsNull()) return Standard_False;
1768   TopoDS_Vertex V1,V2;
1769   TopoDS_Edge E;  TopoDS_Wire W;
1770   ShapeAnalysis_Edge SAE;
1771   if (shape.ShapeType() == TopAbs_EDGE) {
1772     E = TopoDS::Edge (shape);
1773     V1 = SAE.FirstVertex (E);    V2 = SAE.LastVertex  (E);
1774   } else if (shape.ShapeType() == TopAbs_WIRE) {
1775     W = TopoDS::Wire (shape);
1776     ShapeAnalysis::FindBounds (W,V1,V2); 
1777   }
1778   else return Standard_False;
1779   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
1780 //  on va comparer les points avec ceux de thevfirst et thevlast
1781   gp_Pnt p1 = BRep_Tool::Pnt(V1);
1782   gp_Pnt p2 = BRep_Tool::Pnt(V2);
1783
1784   TopoDS_Vertex vfirst = SAE.FirstVertex (myWire->Edge (1)),
1785                 vlast  = SAE.LastVertex (myWire->Edge (NbEdges()));
1786   gp_Pnt pf = BRep_Tool::Pnt(vfirst);
1787   gp_Pnt pl = BRep_Tool::Pnt(vlast);
1788
1789   tailhead = p1.Distance(pl);
1790   tailtail = p2.Distance(pl);
1791   headhead = p1.Distance(pf);
1792   headtail = p2.Distance(pf);
1793   Standard_Real dm1 = tailhead, dm2 = headtail;
1794   Standard_Integer res1 = 0, res2 = 0;
1795
1796   if (tailhead > tailtail) {res1 = 1; dm1 = tailtail;}
1797   if (headtail > headhead) {res2 = 1; dm2 = headhead;}
1798   Standard_Integer result = res1;
1799   myMin3d = Min (dm1, dm2);
1800   myMax3d = Max (dm1, dm2);
1801   if (dm1 > dm2) {dm1 = dm2; result = res2 + 2;}
1802   switch (result) {
1803   case 1: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE2); break;
1804   case 2: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE3); break;
1805   case 3: myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE4); break;
1806   }
1807   if (!res1) myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_DONE5);
1808   if (!res2) myStatus |= ShapeExtend::EncodeStatus (ShapeExtend_DONE6);
1809
1810   if (myMin3d > Max (myPrecision, prec))
1811     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
1812   return LastCheckStatus (ShapeExtend_DONE);
1813 }
1814
1815 //=======================================================================
1816 //function : CheckLoop
1817 //purpose  : 
1818 //=======================================================================
1819 Standard_Boolean isMultiVertex(const TopTools_ListOfShape& alshape,
1820                                const TopTools_MapOfShape& aMapSmallEdges,
1821                                const TopTools_MapOfShape& aMapSeemEdges)
1822 {
1823   TopTools_ListIteratorOfListOfShape lIt1(alshape);
1824   Standard_Integer nbNotAccount =0;
1825   
1826   for( ; lIt1.More() ; lIt1.Next()) 
1827   {
1828     if(aMapSmallEdges.Contains(lIt1.Value()))
1829       nbNotAccount++;
1830     else if(aMapSeemEdges.Contains(lIt1.Value()))
1831       nbNotAccount++;
1832   }
1833   return ((alshape.Extent() -nbNotAccount) >2); 
1834 }
1835  Standard_Boolean ShapeAnalysis_Wire::CheckLoop(TopTools_IndexedMapOfShape& aMapLoopVertices,
1836                                                 TopTools_DataMapOfShapeListOfShape& aMapVertexEdges,
1837                                                 TopTools_MapOfShape& aMapSmallEdges,
1838                                                 TopTools_MapOfShape& aMapSeemEdges) 
1839 {
1840   myStatus = ShapeExtend::EncodeStatus(ShapeExtend_OK);
1841   if (!IsLoaded() || NbEdges() < 2) return Standard_False;
1842   Standard_Real aSavPreci = Precision();
1843   SetPrecision(Precision::Infinite());
1844   Standard_Integer i =1;
1845  
1846   for( ; i <= myWire->NbEdges(); i++) {
1847     TopoDS_Edge aedge = myWire->Edge(i);
1848     TopoDS_Vertex aV1,aV2;
1849     TopExp::Vertices(aedge,aV1,aV2);
1850     Standard_Boolean isSame = aV1.IsSame(aV2);
1851     if(myWire->IsSeam(i))
1852       aMapSeemEdges.Add(aedge); ///continue;
1853     else if(BRep_Tool::Degenerated(aedge))
1854       aMapSmallEdges.Add(aedge);
1855     else if(isSame && CheckSmall(i,BRep_Tool::Tolerance(aV1)))
1856       aMapSmallEdges.Add(aedge);
1857
1858     if(!aMapVertexEdges.IsBound(aV1)) {
1859       TopTools_ListOfShape alshape;
1860       aMapVertexEdges.Bind(aV1,alshape);
1861     }
1862     if(!aMapVertexEdges.IsBound(aV2)) {
1863       TopTools_ListOfShape alshape;
1864       aMapVertexEdges.Bind(aV2,alshape);
1865     }
1866     if(isSame)
1867     {
1868       TopTools_ListOfShape& alshape =  aMapVertexEdges.ChangeFind(aV1);
1869       alshape.Append(aedge);
1870       alshape.Append(aedge);
1871       if(alshape.Extent() >2 && isMultiVertex( alshape,aMapSmallEdges,aMapSeemEdges))
1872         aMapLoopVertices.Add(aV1);
1873     }
1874     else {
1875       TopTools_ListOfShape& alshape =  aMapVertexEdges.ChangeFind(aV1);
1876       alshape.Append(aedge);
1877       if(alshape.Extent() >2 && isMultiVertex( alshape,aMapSmallEdges,aMapSeemEdges))
1878         aMapLoopVertices.Add(aV1);
1879       TopTools_ListOfShape& alshape2 =  aMapVertexEdges.ChangeFind(aV2);
1880       alshape2.Append(aedge);
1881       if(alshape2.Extent() >2 && isMultiVertex( alshape2,aMapSmallEdges,aMapSeemEdges))
1882         aMapLoopVertices.Add(aV2);
1883     }
1884   }
1885   SetPrecision(aSavPreci);
1886   if(aMapLoopVertices.Extent())
1887   {
1888     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
1889     myStatusLoop |= myStatus;
1890     return Standard_True;
1891   }
1892   return Standard_False;
1893 }