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