Integration of OCCT 6.5.0 from SVN
[occt.git] / src / BRepFill / BRepFill_PipeShell.cxx
1 // File:        BRepFill_PipeShell.cxx
2 // Created:     Wed Jul 22 10:52:44 1998
3 // Author:      Philippe MANGIN
4 //              <pmn@sgi29>
5
6 #include <stdio.h>
7
8 #include <BRepFill_PipeShell.ixx>
9
10 #include <BRep_Builder.hxx>
11 #include <BRep_Tool.hxx>
12 #include <TopExp.hxx>
13 #include <TopTools_SequenceOfShape.hxx>
14 #include <TopoDS.hxx>
15 #include <TopoDS_Shell.hxx>
16 #include <TopoDS_Solid.hxx>
17 #include <TopoDS_Iterator.hxx>
18 #include <TopLoc_Location.hxx>
19
20 #include <BRepLib_MakeEdge.hxx>
21 #include <BRepLib_MakeFace.hxx>
22 #include <BRepAdaptor_HCompCurve.hxx>
23 #include <BRepClass3d_SolidClassifier.hxx>
24
25 #include <BRepFill.hxx>
26 #include <BRepFill_Sweep.hxx>
27 #include <BRepFill_SectionPlacement.hxx>
28 #include <BRepFill_Edge3DLaw.hxx>
29 #include <BRepFill_ACRLaw.hxx>
30 #include <BRepFill_EdgeOnSurfLaw.hxx>
31 #include <BRepFill_ShapeLaw.hxx>
32 #include <BRepFill_CompatibleWires.hxx>
33 #include <BRepFill_NSections.hxx>
34 #include <TColStd_HArray1OfReal.hxx>
35
36 #include <GeomFill_TrihedronLaw.hxx>
37 #include <GeomFill_CorrectedFrenet.hxx>
38 #include <GeomFill_Frenet.hxx>
39 #include <GeomFill_Fixed.hxx>
40 #include <GeomFill_ConstantBiNormal.hxx>
41 #include <GeomFill_SectionLaw.hxx>
42 #include <GeomFill_CurveAndTrihedron.hxx>
43 #include <GeomFill_GuideTrihedronAC.hxx>
44 #include <GeomFill_GuideTrihedronPlan.hxx>
45 #include <GeomFill_LocationGuide.hxx>
46
47 //Specif Guide
48 #include <GeomAdaptor_HCurve.hxx>
49
50 #include <gp_Trsf.hxx>
51 #include <gp_Dir.hxx>
52 #include <gp_Vec.hxx>
53 #include <Precision.hxx>
54
55 #include <Standard_NotImplemented.hxx>
56 #include <Standard_ConstructionError.hxx>
57 #include <StdFail_NotDone.hxx>
58
59 #include <BRepBuilderAPI_Copy.hxx>
60
61 #ifdef DRAW
62 #include <Draw.hxx>
63 #include <DrawTrSurf.hxx>
64 #include <DBRep.hxx>
65 static Standard_Boolean Affich = 0;
66 #endif
67
68 #include <TopTools_ListIteratorOfListOfShape.hxx>
69 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
70 #include <TopoDS_Compound.hxx>
71
72 static Standard_Boolean UpdateMap(const TopoDS_Shape&                 theKey,
73                                   const TopoDS_Shape&                 theValue,
74                                   TopTools_DataMapOfShapeListOfShape& theMap);
75
76 static Standard_Boolean BuildBoundaries(const BRepFill_Sweep&               theSweep,
77                                         const Handle(BRepFill_SectionLaw)&  theSection,
78                                         TopoDS_Shape&                       theBottom,
79                                         TopoDS_Shape&                       theTop);
80
81 //=======================================================================
82 //function :  ComputeSection
83 //purpose  : Construit une section intermediaire
84 //=======================================================================
85
86 static Standard_Boolean ComputeSection(const TopoDS_Wire& W1,
87                                        const TopoDS_Wire& W2,
88                                        const Standard_Real p1,
89                                        const Standard_Real p2,
90                                        TopoDS_Wire& Wres)
91 {
92   TColStd_SequenceOfReal SR;
93   TopTools_SequenceOfShape SSh;
94   SR.Clear();
95   SR.Append(0.);
96   SR.Append(1.);
97   SSh.Clear();
98   SSh.Append(W1);
99   SSh.Append(W2);
100   BRepFill_CompatibleWires CW(SSh);
101   CW.SetPercent(0.1);
102   CW.Perform();
103   if (!CW.IsDone()) StdFail_NotDone::Raise("Uncompatible wires");
104   Handle(BRepFill_NSections) SL = new (BRepFill_NSections) (CW.Shape(),SR,0.,1.)
105 ;
106   Standard_Real US = p1/(p1+p2);
107   SL->D0(US, Wres);
108   return Standard_True;
109 }
110
111                                       
112
113 //=======================================================================
114 //function : PerformTransition
115 //purpose  : Modifie une loi de loc en fonction de Transition
116 //=======================================================================
117
118 static void PerformTransition(const BRepFill_TransitionStyle Mode,
119                               Handle(BRepFill_LocationLaw)& Loc,
120                               const Standard_Real angmin)
121 {
122  if (!Loc.IsNull()) {
123    Loc->DeleteTransform();
124    if (Mode == BRepFill_Modified) Loc->TransformInG0Law();
125    else  Loc->TransformInCompatibleLaw(angmin);
126  } 
127 }
128 //=======================================================================
129 //function :  PerformPlan
130 //purpose  : Construit s'il existe un plan de remplissage
131 //=======================================================================
132
133 static Standard_Boolean PerformPlan(TopoDS_Shape& S)
134 {
135   Standard_Boolean isDegen = Standard_True;
136   TopExp_Explorer explo(S, TopAbs_EDGE);
137   for (; explo.More(); explo.Next())
138     {
139       const TopoDS_Edge& anEdge = TopoDS::Edge(explo.Current());
140       if (!BRep_Tool::Degenerated(anEdge))
141         isDegen = Standard_False;
142     }
143   if (isDegen)
144     {
145       S.Nullify();
146       return Standard_True;
147     }
148
149   TopoDS_Wire W = TopoDS::Wire(S);
150   Standard_Boolean Ok = Standard_False;
151   if (!W.IsNull()) {
152     BRepLib_MakeFace mkplan(W, Standard_True);
153     if (mkplan.IsDone()) {
154       S = mkplan.Face();
155       Ok = Standard_True;
156     }
157   }
158  return Ok;
159 }
160
161 //=============================================================================
162 //function :  IsSameOriented
163 //purpose  : Checks whether aFace is oriented to the same side as aShell or not
164 //=============================================================================
165
166 static Standard_Boolean IsSameOriented(const TopoDS_Shape& aFace,
167                                        const TopoDS_Shape& aShell)
168 {
169   TopExp_Explorer Explo(aFace, TopAbs_EDGE);
170   TopoDS_Shape anEdge = Explo.Current();
171   TopAbs_Orientation Or1 = anEdge.Orientation();
172
173   TopTools_IndexedDataMapOfShapeListOfShape EFmap;
174   TopExp::MapShapesAndAncestors( aShell, TopAbs_EDGE, TopAbs_FACE, EFmap );
175
176   const TopoDS_Shape& AdjacentFace = EFmap.FindFromKey(anEdge).First();
177   TopoDS_Shape theEdge;
178   for (Explo.Init(AdjacentFace, TopAbs_EDGE); Explo.More(); Explo.Next())
179     {
180       theEdge = Explo.Current();
181       if (theEdge.IsSame(anEdge))
182         break;
183     }
184
185   TopAbs_Orientation Or2 = theEdge.Orientation();
186   if (Or1 == Or2)
187     return Standard_False;
188   return Standard_True;
189 }
190 //=======================================================================
191 //function : BRepFill_PipeShell
192 //purpose  : 
193 //=======================================================================
194 BRepFill_PipeShell::BRepFill_PipeShell(const TopoDS_Wire& Spine)
195                       :  mySpine(Spine), 
196                          myTrihedron(GeomFill_IsCorrectedFrenet),
197                          myTransition(BRepFill_Modified),
198                          myStatus(GeomFill_PipeOk)
199 {
200   myLocation.Nullify();
201   mySection.Nullify();
202   myLaw.Nullify();
203   SetTolerance();
204
205   // Attention aux wire closed non declare !
206   if (!mySpine.Closed()) {
207     TopoDS_Vertex Vf, Vl;
208     TopExp::Vertices(mySpine, Vf, Vl);
209     if (Vf.IsSame(Vl)) mySpine.Closed(Standard_True);
210   }  
211 }
212
213 //=======================================================================
214 //function : Set
215 //purpose  : Definie une loi de Frenet (Corrige)
216 //=======================================================================
217  void BRepFill_PipeShell::Set(const Standard_Boolean IsFrenet) 
218 {
219   Handle(GeomFill_TrihedronLaw) TLaw;
220   if (IsFrenet) {
221     myTrihedron = GeomFill_IsFrenet;
222     TLaw = new (GeomFill_Frenet) ();
223   }
224   else {
225     myTrihedron = GeomFill_IsFrenet;
226     TLaw = new (GeomFill_CorrectedFrenet) ();
227   }
228   Handle(GeomFill_CurveAndTrihedron) Loc = 
229     new (GeomFill_CurveAndTrihedron) (TLaw);
230   myLocation = new (BRepFill_Edge3DLaw) (mySpine, Loc);
231   mySection.Nullify(); //Il faut relocaliser les sections.
232 }
233
234 //=======================================================================
235 //function : Set
236 //purpose  : Definie une loi Constante
237 //=======================================================================
238  void BRepFill_PipeShell::Set(const gp_Ax2& Axe) 
239 {
240   myTrihedron = GeomFill_IsFixed;
241   gp_Vec V1, V2;
242   V1.SetXYZ(Axe.Direction().XYZ());
243   V2.SetXYZ(Axe.XDirection().XYZ());
244   Handle(GeomFill_Fixed) TLaw = new (GeomFill_Fixed) (V1, V2);
245   Handle(GeomFill_CurveAndTrihedron) Loc = 
246     new (GeomFill_CurveAndTrihedron) (TLaw);
247   myLocation = new (BRepFill_Edge3DLaw) (mySpine, Loc); 
248   mySection.Nullify(); //Il faut relocaliser les sections.
249 }
250
251 //=======================================================================
252 //function : Set
253 //purpose  : Construit une loi de location de type binormal fixe
254 //=======================================================================
255  void BRepFill_PipeShell::Set(const gp_Dir& BiNormal) 
256 {
257   myTrihedron = GeomFill_IsConstantNormal;
258
259   Handle(GeomFill_ConstantBiNormal) TLaw = 
260     new (GeomFill_ConstantBiNormal) (BiNormal);
261   Handle(GeomFill_CurveAndTrihedron) Loc = 
262     new (GeomFill_CurveAndTrihedron) (TLaw);
263   myLocation = new (BRepFill_Edge3DLaw) (mySpine, Loc); 
264   mySection.Nullify(); //Il faut relocaliser les sections.
265 }
266
267 //=======================================================================
268 //function : Set
269 //purpose  : Construit une loi de location de type Darboux
270 //=======================================================================
271  Standard_Boolean BRepFill_PipeShell::Set(const TopoDS_Shape& SpineSupport) 
272 {
273  Standard_Boolean B;
274
275   // Il faut une loi de location speciale
276  Handle(BRepFill_EdgeOnSurfLaw) loc = 
277    new (BRepFill_EdgeOnSurfLaw) (mySpine, SpineSupport);
278  B = loc->HasResult();
279  if (B) {
280    myLocation = loc; 
281    myTrihedron = GeomFill_IsDarboux;
282    mySection.Nullify(); //Il faut relocaliser les sections.
283  }
284  return B;
285 }
286
287 //=======================================================================
288 //function : Set
289 //purpose  : Definit une loi a l'aide d'un contour guide
290 //=======================================================================
291  void BRepFill_PipeShell::Set(const TopoDS_Wire& AuxiliarySpine,
292                               const Standard_Boolean CurvilinearEquivalence,
293                               const Standard_Boolean KeepContact) 
294 {  
295   // Reorganisation du guide (pb d'orientation et d'origine)
296   TopoDS_Wire TheGuide;
297   TheGuide =  AuxiliarySpine;
298   Standard_Boolean SpClose = mySpine.Closed(), 
299                    GuideClose = AuxiliarySpine.Closed();
300
301   if (!SpClose && !GuideClose) {
302     // Cas ouvert reorientation du guide
303     TopoDS_Wire sp = mySpine;
304     TopTools_SequenceOfShape Seq;
305     Seq.Append(sp);
306     Seq.Append(TheGuide);
307     BRepFill_CompatibleWires CW(Seq);
308     CW.SetPercent(0.1);
309     CW.Perform();
310     if (!CW.IsDone()) StdFail_NotDone::Raise("Uncompatible wires");
311     TheGuide = TopoDS::Wire(CW.Shape().Value(2));
312   }
313   else if (GuideClose) {
314     // Cas guide ferme : Determination de l'origine 
315     // & reorientation du guide
316     gp_Vec Dir;
317     gp_Pnt SpOr;
318     if (!SpClose) {
319       TopoDS_Vertex Vf, Vl;
320       gp_Pnt P;
321       TopExp::Vertices(mySpine, Vf, Vl);
322       SpOr = BRep_Tool::Pnt(Vf);
323       P = BRep_Tool::Pnt(Vl);
324       gp_Vec V(P, SpOr);
325       SpOr.BaryCenter(0.5, P, 0.5);
326       Dir = V;
327     }
328     else {
329       BRepAdaptor_CompCurve BC(mySpine);
330       BC.D1(0,SpOr,Dir); 
331     } 
332     BRepFill::SearchOrigin(TheGuide, SpOr, Dir, 100*myTol3d);
333   }
334
335 #ifdef DRAW
336   if (Affich)
337     DBRep::Set("theguide", TheGuide);
338 #endif
339   // on transforme le guide en 1 seule courbe (periodic si posssible)
340   Handle(BRepAdaptor_HCompCurve) Guide  = 
341     new (BRepAdaptor_HCompCurve) (TheGuide);
342   Guide->ChangeCurve().SetPeriodic(Standard_True);
343
344   if (CurvilinearEquivalence) { // triedre par abscisse curviligne reduite
345     if (KeepContact) 
346       myTrihedron = GeomFill_IsGuideACWithContact; // avec rotation 
347     else
348       myTrihedron = GeomFill_IsGuideAC; // sans rotation 
349       
350     Handle(GeomFill_GuideTrihedronAC) TLaw
351       = new (GeomFill_GuideTrihedronAC) (Guide);
352     Handle(GeomFill_LocationGuide) Loc = 
353       new (GeomFill_LocationGuide) (TLaw);      
354     myLocation = new (BRepFill_ACRLaw) (mySpine, Loc);  
355   }
356   else {// triedre par plan
357     if (KeepContact) 
358       myTrihedron = GeomFill_IsGuidePlanWithContact; // avec rotation 
359     else 
360       myTrihedron = GeomFill_IsGuidePlan; // sans rotation
361
362     Handle(GeomFill_GuideTrihedronPlan) TLaw = 
363       new (GeomFill_GuideTrihedronPlan) (Guide);    
364     Handle(GeomFill_LocationGuide) Loc = 
365       new (GeomFill_LocationGuide) (TLaw);
366     myLocation = new (BRepFill_Edge3DLaw) (mySpine, Loc);  
367   }    
368   mySection.Nullify(); //Il faut relocaliser les sections.
369 }
370
371 //=======================================================================
372 //function : Add
373 //purpose  : Ajoute une Section
374 //=======================================================================
375  void BRepFill_PipeShell::Add(const TopoDS_Shape& Profile,
376                               const Standard_Boolean WithContact,
377                               const Standard_Boolean WithCorrection) 
378
379   TopoDS_Vertex V;
380   V.Nullify();
381   Add(Profile, V, WithContact, WithCorrection);
382   ResetLoc();
383 }
384
385 //=======================================================================
386 //function : Add
387 //purpose  : Ajoute une Section
388 //=======================================================================
389  void BRepFill_PipeShell::Add(const TopoDS_Shape& Profile,
390                               const TopoDS_Vertex& Location,
391                               const Standard_Boolean WithContact,
392                               const Standard_Boolean WithCorrection) 
393 {
394  Delete(Profile); // Pas de duplication
395  BRepFill_Section S (Profile, Location, WithContact, WithCorrection);
396  mySeq.Append(S);
397  mySection.Nullify();
398  ResetLoc();
399 }
400
401 //=======================================================================
402 //function : SetLaw
403 //purpose  : Section + Loi d'homothetie
404 //=======================================================================
405  void BRepFill_PipeShell::SetLaw(const TopoDS_Shape& Profile,
406                                  const Handle(Law_Function)& L,
407                                  const Standard_Boolean WithContact,
408                                  const Standard_Boolean WithCorrection) 
409 {
410  TopoDS_Vertex V;
411  V.Nullify();
412  SetLaw( Profile, L, V, WithContact, WithCorrection);
413  ResetLoc();
414 }
415
416 //=======================================================================
417 //function : SetLaw
418 //purpose  :  Section + Loi d'homothetie
419 //=======================================================================
420  void BRepFill_PipeShell::SetLaw(const TopoDS_Shape& Profile,
421                                  const Handle(Law_Function)& L,
422                                  const TopoDS_Vertex& Location,
423                                  const Standard_Boolean WithContact,
424                                  const Standard_Boolean WithCorrection) 
425 {
426   mySeq.Clear();
427   BRepFill_Section S (Profile, Location, WithContact, WithCorrection);
428   S.Set(Standard_True);
429   mySeq.Append(S);
430   myLaw = L;
431   mySection.Nullify();
432   ResetLoc();
433 }
434
435 //=======================================================================
436 //function : Delete
437 //purpose  : Supprime une section
438 //=======================================================================
439  void BRepFill_PipeShell::Delete(const TopoDS_Shape&  Profile)
440 {
441   Standard_Boolean isVertex = (Profile.ShapeType() == TopAbs_VERTEX);
442
443   Standard_Boolean Trouve=Standard_False;
444   Standard_Integer ii;
445   for (ii=1; ii<=mySeq.Length() && !Trouve; ii++) {
446     Standard_Boolean found = Standard_False;
447     const TopoDS_Wire& aWire = mySeq.Value(ii).Wire();
448     if (isVertex)
449       {
450         TopExp_Explorer Explo(aWire, TopAbs_VERTEX);
451         for (; Explo.More(); Explo.Next())
452           if (Profile.IsSame(Explo.Current()))
453             found = Standard_True;
454       }
455     else if (Profile.IsSame(aWire))
456       found = Standard_True;
457     
458     if (found)
459       {
460         Trouve = Standard_True;
461         mySeq.Remove(ii);
462       }
463   }
464
465   if (Trouve) mySection.Nullify();
466   ResetLoc();
467 }
468
469
470 //=======================================================================
471 //function : IsReady
472 //purpose  : 
473 //=======================================================================
474  Standard_Boolean BRepFill_PipeShell::IsReady() const
475 {
476  return (mySeq.Length() != 0);
477 }
478 //=======================================================================
479 //function : GetStatus
480 //purpose  : 
481 //=======================================================================
482  GeomFill_PipeError BRepFill_PipeShell::GetStatus() const
483 {
484  return myStatus;
485 }
486
487
488 //=======================================================================
489 //function : SetTolerance
490 //purpose  :
491 //=======================================================================
492  void BRepFill_PipeShell::SetTolerance(const Standard_Real Tol3d  ,
493                                        const Standard_Real BoundTol, 
494                                        const Standard_Real TolAngular)
495 {
496  myTol3d = Tol3d;
497  myBoundTol =  BoundTol;
498  myTolAngular = TolAngular;
499 }
500
501 //=======================================================================
502 //function : SetTransition
503 //purpose  : Definit le mode de traitement des coins
504 //=======================================================================
505  void BRepFill_PipeShell::SetTransition(const BRepFill_TransitionStyle Mode,
506                                         const Standard_Real Angmin,
507                                         const Standard_Real Angmax)
508 {
509  if (myTransition != Mode) 
510    mySection.Nullify(); //Il faut relocaliser les sections.
511  myTransition = Mode;
512  angmin =  Angmin;
513  angmax = Angmax;
514 }  
515
516 //=======================================================================
517 //function : Simulate
518 //purpose  : Calcul N Sections
519 //=======================================================================
520  void BRepFill_PipeShell::Simulate(const Standard_Integer N, 
521                                    TopTools_ListOfShape& List)
522 {
523   // Preparation
524   Prepare();
525   List.Clear();
526
527   Standard_Real First, Last, Length, Delta, U, 
528                 US, DeltaS,FirstS;
529   Standard_Integer ii, NbL = myLocation->NbLaw();
530   Standard_Boolean Finis=Standard_False;
531   TopoDS_Shape W;
532   
533   // Calcul des parametres de digitalisation
534   mySection->Law(1)->GetDomain(FirstS, Last);
535   DeltaS = Last - FirstS; 
536   myLocation->CurvilinearBounds(NbL,First, Length);
537   Delta = Length;
538   if (N>1) Delta /= (N-1);
539
540   myLocation->CurvilinearBounds(1,First, Last); // Init de Last
541   for (U=0.0, ii=1; !Finis ; U+=Delta) {
542     if (U >= Length) {
543       U = Length;
544       Finis = Standard_True;
545     }
546     else {
547       if (ii <  NbL) myLocation->CurvilinearBounds(NbL,First, Last);
548       if (U > Last) U = (Last+First)/2; // On ne saute pas une arete
549       if (U> First) ii++;
550     }
551     US = FirstS + (U/Length)*DeltaS;
552     // Calcul d'une section
553     mySection->D0(US, W);
554     myLocation->D0(U, W);
555     List.Append(W);
556   } 
557 }
558
559 //=======================================================================
560 //function : Build
561 //purpose  : Construit le Shell et l'historique
562 //=======================================================================
563  Standard_Boolean BRepFill_PipeShell::Build() 
564 {
565   Standard_Boolean Ok;
566   Standard_Real FirstS, LastS;
567   // 1) Preparation
568   Prepare();
569
570   if (myStatus != GeomFill_PipeOk) {
571     BRep_Builder B;
572     TopoDS_Shell Sh;
573     B.MakeShell(Sh); 
574     myShape = Sh; // Nullify
575     return Standard_False; 
576   }
577
578   // 2) Calcul de myFirst et myLast
579   mySection->Law(1)->GetDomain(FirstS, LastS);
580   mySection->D0(FirstS, myFirst);
581   myLocation->D0(0, myFirst);
582   if (mySection->IsVClosed() && myLocation->IsClosed()) {
583       if (myLocation->IsG1(0)>=0) 
584         myLast = myFirst;
585       else {
586         myFirst.Nullify();
587         myLast.Nullify();
588       }
589   }
590   else {
591     Standard_Real Length;
592     myLocation->CurvilinearBounds(myLocation->NbLaw(), 
593                                   FirstS, Length);
594     mySection->D0(LastS,   myLast);
595     myLocation->D0(Length, myLast);
596     // eap 5 Jun 2002 occ332, myLast and myFirst must not share one TShape,
597     // tolerances of shapes built on them may be quite different
598     if (myFirst.IsPartner( myLast )) {
599       BRepBuilderAPI_Copy copy(myLast);
600       if (copy.IsDone()) 
601         myLast = copy.Shape();
602     }
603     // eap 5 Jun 2002 occ332, end modif
604   }
605 #if DRAW
606   if (Affich) {
607     DBRep::Set("PipeFirst", myFirst);
608     DBRep::Set("PipeLast",  myLast);
609   }
610 #endif
611
612   // 3) Construction
613   BRepFill_Sweep MkSw(mySection, myLocation, Standard_True);
614   MkSw.SetTolerance(myTol3d, myBoundTol, 1.e-5, myTolAngular);
615   MkSw.SetAngularControl(angmin, angmax);
616   MkSw.SetBounds(TopoDS::Wire(myFirst), 
617                  TopoDS::Wire(myLast));
618   MkSw.Build(myTransition);
619
620   myStatus = myLocation->GetStatus();
621   Ok =  (MkSw.IsDone() && (myStatus == GeomFill_PipeOk));
622
623   if (Ok) {
624     myShape = MkSw.Shape();
625
626     TopoDS_Shape aBottomWire = myFirst;
627     TopoDS_Shape aTopWire    = myLast;
628
629     if(BuildBoundaries(MkSw, mySection, aBottomWire, aTopWire)) {
630       myFirst = aBottomWire;
631       myLast = aTopWire;
632     }
633     
634     if (mySection->IsUClosed())
635       {
636         TopExp_Explorer explo;
637         Standard_Boolean DegenFirst = Standard_True, DegenLast = Standard_True;
638
639         for (explo.Init(myFirst, TopAbs_EDGE); explo.More(); explo.Next())
640           {
641             const TopoDS_Edge& anEdge = TopoDS::Edge(explo.Current());
642             DegenFirst = DegenFirst && BRep_Tool::Degenerated(anEdge);
643           }
644
645         for (explo.Init(myLast, TopAbs_EDGE); explo.More(); explo.Next())
646           {
647             const TopoDS_Edge& anEdge = TopoDS::Edge(explo.Current());
648             DegenLast = DegenLast && BRep_Tool::Degenerated(anEdge);
649           }
650
651         if (DegenFirst && DegenLast)
652           myShape.Closed(Standard_True);
653       }
654
655     BuildHistory(MkSw);
656   }
657   else {
658     BRep_Builder B;
659     TopoDS_Shell Sh;
660     B.MakeShell(Sh); 
661     myShape = Sh; // Nullify
662     if (myStatus == GeomFill_PipeOk) myStatus = GeomFill_PipeNotOk;
663   }
664   return Ok;
665 }
666
667 //=======================================================================
668 //function : MakeSolid
669 //purpose  : 
670 //=======================================================================
671  Standard_Boolean BRepFill_PipeShell::MakeSolid() 
672
673   if (myShape.IsNull()) 
674     StdFail_NotDone::Raise("PipeShell is not build");
675   Standard_Boolean B = myShape.Closed();
676   BRep_Builder BS;
677
678   if (!B)
679     {
680       if(!myFirst.IsNull() && !myLast.IsNull()) {
681         B = (myFirst.Closed() && myLast.Closed());
682       }
683       if (B) {
684         // Il faut boucher les extremites 
685         B =  PerformPlan(myFirst);
686         if (B) {
687           B =  PerformPlan(myLast);
688           if (B) {
689             if (!myFirst.IsNull() && !IsSameOriented( myFirst, myShape ))
690               myFirst.Reverse();
691             if (!myLast.IsNull() && !IsSameOriented( myLast, myShape ))
692               myLast.Reverse();
693
694             if (!myFirst.IsNull())
695               BS.Add(myShape, TopoDS::Face(myFirst));
696             if (!myLast.IsNull())
697               BS.Add(myShape, TopoDS::Face(myLast));
698
699             myShape.Closed(Standard_True);
700           }
701         }
702       }
703     }
704
705   if (B) {
706    TopoDS_Solid solid;
707    BS.MakeSolid(solid);
708    BS.Add(solid,TopoDS::Shell(myShape));
709    BRepClass3d_SolidClassifier SC(solid);
710    SC.PerformInfinitePoint(Precision::Confusion());
711    if ( SC.State() == TopAbs_IN) {
712      BS.MakeSolid(solid);
713      myShape.Reverse();
714      BS.Add(solid,TopoDS::Shell(myShape));
715    }
716    myShape = solid;   
717    myShape.Closed(Standard_True);
718  }
719   return B;
720 }
721
722 //=======================================================================
723 //function : Shape
724 //purpose  : Renvoi le resultat
725 //=======================================================================
726 const TopoDS_Shape& BRepFill_PipeShell::Shape() const
727 {
728   return myShape;
729 }
730
731 //=======================================================================
732 //function : FirstShape
733 //purpose  : Renvoi la section du debut
734 //=======================================================================
735 const TopoDS_Shape& BRepFill_PipeShell::FirstShape() const
736 {
737   return myFirst;
738 }
739
740 //=======================================================================
741 //function : LastShape
742 //purpose  : Renvoi la section de fin
743 //=======================================================================
744 const TopoDS_Shape& BRepFill_PipeShell::LastShape() const
745 {
746  return myLast;
747 }
748
749 //=======================================================================
750 //function : Generated
751 //purpose  : 
752 //=======================================================================
753 //  void BRepFill_PipeShell::Generated(const TopoDS_Shape& ,
754 //                                  TopTools_ListOfShape& ) 
755 void BRepFill_PipeShell::Generated(const TopoDS_Shape&   theShape,
756                                    TopTools_ListOfShape& theList) 
757 {
758   //   Standard_NotImplemented::Raise("Generated:Pas Fait"); 
759   theList.Clear();
760
761   if(myGenMap.IsBound(theShape)) {
762     theList = myGenMap.Find(theShape);
763   } 
764 }
765
766 //=======================================================================
767 //function : Prepare
768 //purpose  : - Verifie que tout est pret
769 //           - Construit la loi de section
770 //           - Construit la loi de location si necessaire
771 //           - Calcul First & Last
772 //=======================================================================
773  void BRepFill_PipeShell::Prepare() 
774 {
775   TopoDS_Wire theSect;
776   if (!IsReady()) StdFail_NotDone::Raise("PipeShell");
777   if (!myLocation.IsNull() && !mySection.IsNull()) return; // C'est deja pret
778  
779   //Check set of section for right configuration of punctual sections
780   Standard_Integer i;
781   TopoDS_Iterator iter;;
782   for (i = 2; i <= mySeq.Length()-1; i++)
783     {
784       Standard_Boolean wdeg = Standard_True;
785       for (iter.Initialize(mySeq(i).Wire()); iter.More(); iter.Next())
786         {
787           const TopoDS_Edge& anEdge = TopoDS::Edge(iter.Value());
788           wdeg = wdeg && (BRep_Tool::Degenerated(anEdge));
789         }
790       if (wdeg)
791         Standard_Failure::Raise("Wrong usage of punctual sections");
792     }
793   if (mySeq.Length() <= 2)
794     {
795       Standard_Boolean wdeg = Standard_True;
796       for (i = 1; i <= mySeq.Length(); i++)
797         for (iter.Initialize(mySeq(i).Wire()); iter.More(); iter.Next())
798           {
799             const TopoDS_Edge& anEdge = TopoDS::Edge(iter.Value());
800             wdeg = wdeg && (BRep_Tool::Degenerated(anEdge));
801           }
802       if (wdeg)
803         Standard_Failure::Raise("Wrong usage of punctual sections");
804     }
805
806   // Construction de la loi de location  
807   if(myLocation.IsNull()) 
808     {
809       switch(myTrihedron)
810         {
811         case GeomFill_IsCorrectedFrenet :
812           {
813             Handle(GeomFill_TrihedronLaw) TLaw = 
814               new (GeomFill_CorrectedFrenet) ();
815             Handle(GeomFill_CurveAndTrihedron) Loc = 
816               new (GeomFill_CurveAndTrihedron) (TLaw);
817             myLocation = new (BRepFill_Edge3DLaw) (mySpine, Loc);
818             break;
819           } 
820           default :
821             { // Pas prevu !
822               Standard_ConstructionError::Raise("PipeShell");
823             }
824         }
825     }  
826   
827   //Transformation de la loi (Gestion Transition)
828   PerformTransition(myTransition, myLocation, angmin);
829
830   
831  // Construction de la loi de section
832   if (mySeq.Length() == 1) {
833     Standard_Real p1;
834     Place(mySeq(1), theSect,p1);
835     TopoDS_Wire aLocalShape = theSect;
836     if (mySeq(1).IsLaw())
837       mySection = new BRepFill_ShapeLaw(aLocalShape, myLaw);
838 //      mySection = new (BRepFill_ShapeLaw) (TopoDS_Wire(theSect), myLaw);
839     else 
840       mySection = new BRepFill_ShapeLaw(aLocalShape);
841 // mySection = new (BRepFill_ShapeLaw) (TopoDS::Wire(theSect));
842     }   
843   else 
844     {
845       TColStd_SequenceOfReal Param;
846       TopTools_SequenceOfShape WSeq;
847       WSeq.Clear();
848       Param.Clear();
849       Standard_Integer NbL = myLocation->NbLaw();
850       Standard_Real V1, V2, param;
851       myLocation->CurvilinearBounds(NbL, V1, V2);
852       V1 = 0.;
853       Standard_Integer ideb = 0, ifin = 0;
854 //      for (Standard_Integer iseq=1;iseq<=mySeq.Length();iseq++) {
855       Standard_Integer iseq;
856       for (iseq=1;iseq<=mySeq.Length();iseq++) {
857         Place(mySeq(iseq), theSect, param);
858         Param.Append(param);
859         WSeq.Append(theSect);
860 //      WSeq.Append(TopoDS::Wire(theSect));
861         if (param==V1) ideb = iseq;
862         if (param==V2) ifin = iseq;
863       }
864       
865
866       // sections bouclantes ?
867       if (myLocation->IsClosed()) {
868         if (ideb>0) {
869           // on place la section initiale en position finale
870           Param.Append(V2);
871           WSeq.Append(WSeq(ideb));
872         }
873         else if (ifin>0) {
874           // on place la section finale en position initiale
875           Param.Append(V1);
876           WSeq.Append(WSeq(ifin));
877         }
878         else {
879           // il faut trouver une section moyenne a imposer en V1 et en V2
880           Standard_Real pmin = Param.Value(1), pmax = Param.Value(1);
881           TopoDS_Wire Wmin = TopoDS::Wire(WSeq.Value(1)), Wmax;
882           for (iseq=2;iseq<=WSeq.Length();iseq++) {
883             if (Param.Value(iseq)<pmin) {
884               pmin = Param.Value(iseq);
885               Wmin = TopoDS::Wire(WSeq.Value(iseq));
886             }
887             if (Param.Value(iseq)>pmax) {
888               pmax = Param.Value(iseq);
889               Wmax = TopoDS::Wire(WSeq.Value(iseq));
890             }
891           }
892           // section moyenne entre Wmin et Wmax
893           TopoDS_Wire Wres;
894           Standard_Real dmin = Abs(pmin-V1);
895           Standard_Real dmax = Abs(pmax-V2);
896           if (ComputeSection(Wmin,Wmax,dmin,dmax,Wres)) {
897             // on impose la section Wres au debut et a la fin
898             Param.Append(V1);
899             WSeq.Append(Wres);
900             Param.Append(V2);
901             WSeq.Append(Wres);
902             
903           }
904           
905         }
906       }
907
908       // tri des sections par parametre croissant
909       Standard_Boolean play_again = Standard_True;
910       while (play_again) {
911         play_again = Standard_False;
912         for (iseq=1;iseq<=WSeq.Length();iseq++) {
913           for (Standard_Integer jseq=iseq+1;jseq<=WSeq.Length();jseq++) {
914             if (Param.Value(iseq)>Param.Value(jseq)) {
915               Param.Exchange(iseq,jseq);
916               WSeq.Exchange(iseq,jseq);
917               play_again = Standard_True;
918             }
919           }
920         }
921       }
922
923 #ifdef DRAW
924   if ( Affich) {
925     char*  name = new char[100];
926     Standard_Integer NBSECT = 0;
927     for (Standard_Integer i=1;i<=WSeq.Length();i++) {
928       NBSECT++;
929       sprintf(name,"WSeq_%d",NBSECT);
930       DBRep::Set(name,TopoDS::Wire(WSeq.Value(i)));
931     }
932   }
933 #endif
934       
935       
936
937       //  Calcul des sections de travail
938       TopTools_SequenceOfShape WorkingSections;
939       WorkingSections.Clear();
940       TopTools_DataMapOfShapeListOfShape WorkingMap;
941       WorkingMap.Clear();
942       BRepFill_CompatibleWires Georges(WSeq);
943       Georges.SetPercent(0.1);
944       Georges.Perform(Standard_False);
945       if (Georges.IsDone()) {
946         WorkingSections = Georges.Shape();
947         WorkingMap = Georges.Generated();
948       }
949       else {
950         Standard_ConstructionError::Raise("PipeShell : uncompatible wires");
951       }
952       mySection = new (BRepFill_NSections) (WorkingSections,Param,V1,V2);
953       
954     }// else
955
956   // on modifie la loi de location si contact
957   if ( (myTrihedron == GeomFill_IsGuidePlanWithContact)
958       || (myTrihedron == GeomFill_IsGuideACWithContact) )  {
959     Standard_Real fs, f, l, Delta, Length;
960     Handle(GeomFill_LocationGuide) Loc;
961     Handle(GeomFill_SectionLaw) Sec = mySection->ConcatenedLaw();
962     myLocation->CurvilinearBounds(myLocation->NbLaw(), f, Length);
963     Sec->GetDomain(fs,l);
964     Delta = (l-fs)/Length;
965
966     Standard_Real angle, old_angle = 0;
967     for (Standard_Integer ipath=1; ipath<=myLocation->NbLaw(); ipath++) {
968       myLocation->CurvilinearBounds(ipath, f, l);
969       Loc = Handle(GeomFill_LocationGuide)::DownCast(myLocation->Law(ipath));
970       Loc->Set(Sec, Standard_True, fs + f*Delta, fs + l*Delta,
971                old_angle, angle); // on force la rotation       
972       old_angle = angle;
973     }      
974   }
975
976   myStatus = myLocation->GetStatus();
977 }
978
979 //=======================================================================
980 //function : Place
981 //purpose  : Met en Place une Section dans le repere local
982 //           et retourne son parametre sur la trajectoire
983 //=======================================================================
984 void BRepFill_PipeShell::Place(const BRepFill_Section& Sec,
985                                TopoDS_Wire& W,
986                                Standard_Real& param)
987 {
988   BRepFill_SectionPlacement Place(myLocation, 
989                                   Sec.Wire(),
990                                   Sec.Vertex(),
991                                   Sec.WithContact(),
992                                   Sec.WithCorrection());
993   W =  Sec.Wire();
994   TopLoc_Location Loc2(Place.Transformation()), Loc1;
995   Loc1 = W.Location();
996   W.Location(Loc2.Multiplied(Loc1));
997   param = Place.AbscissaOnPath();
998 }
999
1000
1001 //=======================================================================
1002 //function : ResetLoc
1003 //purpose  : Supprime les references aux sections dans les loi de location
1004 //=======================================================================
1005  void BRepFill_PipeShell::ResetLoc() 
1006 {
1007   if ( (myTrihedron == GeomFill_IsGuidePlanWithContact)
1008       || (myTrihedron == GeomFill_IsGuideACWithContact) ) {
1009     Handle(GeomFill_LocationGuide) Loc;
1010     for (Standard_Integer isec=1; isec<=myLocation->NbLaw(); isec++) { 
1011       Loc = Handle(GeomFill_LocationGuide)::DownCast(myLocation->Law(isec));
1012       Loc->EraseRotation();// on supprime la rotation   
1013     }    
1014   }
1015 }
1016
1017 //=======================================================================
1018 //function : BuildHistory
1019 //purpose  : Builds history for edges of spine, 
1020 //           for built bottom shape of sweep,
1021 //           for boundary vertices of bottom shape of sweep,
1022 //           for boundary profiles
1023 //=======================================================================
1024 void BRepFill_PipeShell::BuildHistory(const BRepFill_Sweep& theSweep) 
1025 {
1026   Handle(TopTools_HArray2OfShape) aFaces = theSweep.SubShape();
1027   Handle(TopTools_HArray2OfShape) aVEdges = theSweep.Sections();
1028   Handle(TopTools_HArray2OfShape) aUEdges = theSweep.InterFaces();
1029   Standard_Integer i = 0, j = 0;
1030   Standard_Boolean bPrevModified = Standard_False;
1031
1032   for(i = 1; i <= mySection->NbLaw(); i++) {
1033     if((!aVEdges->Value(i, 1).IsNull()) && (aVEdges->Value(i, 1).ShapeType() == TopAbs_FACE)) {
1034       bPrevModified = Standard_True;
1035       break;
1036     }
1037   }
1038
1039   for(j = myLocation->NbLaw(); j >= 1; j--) {
1040     Standard_Boolean ismodified = Standard_False;
1041     TopTools_ListOfShape aListOfFace;
1042
1043     if(bPrevModified) {
1044       for(i = 1; i <= mySection->NbLaw(); i++) {
1045         Standard_Integer lessindex = j + 1;
1046         lessindex = (lessindex > myLocation->NbLaw()) ? 1 : lessindex;
1047
1048         if((!aVEdges->Value(i, lessindex).IsNull()) && (aVEdges->Value(i, lessindex).ShapeType() == TopAbs_FACE)) {
1049           aListOfFace.Append(aVEdges->Value(i, lessindex));
1050           const TopoDS_Shape& aBottomEdge = aVEdges->Value(i, 1);
1051
1052           if((!aBottomEdge.IsNull()) && (aBottomEdge.ShapeType() == TopAbs_EDGE)) {
1053             UpdateMap(aBottomEdge, aVEdges->Value(i, lessindex), myGenMap);
1054           }
1055         }
1056       }
1057     }
1058     bPrevModified = Standard_False;
1059
1060     for(i = 1; i <= mySection->NbLaw(); i++) {
1061       if((!aVEdges->Value(i, j).IsNull()) && (aVEdges->Value(i, j).ShapeType() == TopAbs_FACE)) {
1062         aListOfFace.Append(aVEdges->Value(i, j));
1063         bPrevModified = Standard_True;
1064
1065         const TopoDS_Shape& aBottomEdge = aVEdges->Value(i, 1);
1066
1067         if((!aBottomEdge.IsNull()) && (aBottomEdge.ShapeType() == TopAbs_EDGE)) {
1068           UpdateMap(aBottomEdge, aVEdges->Value(i, j), myGenMap);
1069         }
1070       }
1071
1072       if(aFaces->Value(i, j).ShapeType() == TopAbs_FACE) {
1073         aListOfFace.Append(aFaces->Value(i, j));
1074         const TopoDS_Shape& aBottomEdge = aVEdges->Value(i, 1);
1075
1076         if((!aBottomEdge.IsNull()) && (aBottomEdge.ShapeType() == TopAbs_EDGE)) {
1077           UpdateMap(aBottomEdge, aFaces->Value(i, j), myGenMap);
1078         }
1079       }
1080     }
1081
1082     if(!myGenMap.IsBound(myLocation->Edge(j)))
1083       myGenMap.Bind(myLocation->Edge(j), aListOfFace);
1084     else
1085       myGenMap.ChangeFind(myLocation->Edge(j)).Append(aListOfFace);
1086
1087     // build history for free booundaries.begin
1088     if(!mySection->IsUClosed()) {
1089       TopoDS_Compound aFaceComp;
1090       BRep_Builder aB;
1091       aB.MakeCompound(aFaceComp);
1092       TopTools_ListIteratorOfListOfShape anIt(aListOfFace);
1093
1094       for(; anIt.More(); anIt.Next()) {
1095         aB.Add(aFaceComp, anIt.Value());
1096       }
1097       TopTools_IndexedDataMapOfShapeListOfShape aMapEF;
1098       TopExp::MapShapesAndAncestors(aFaceComp, TopAbs_EDGE, TopAbs_FACE, aMapEF);
1099       Standard_Integer eit = 0;
1100
1101       for(eit = aUEdges->LowerRow(); eit <= aUEdges->UpperRow(); eit++) {
1102         const TopoDS_Shape& aShape = aUEdges->Value(eit, j);
1103
1104         if(aMapEF.Contains(aShape)) {
1105           const TopTools_ListOfShape& aList = aMapEF.FindFromKey(aShape);
1106
1107           if(aList.Extent() < 2) {
1108             UpdateMap(myLocation->Edge(j), aShape, myGenMap);
1109
1110             TopoDS_Shape aGenVertex;
1111             TopTools_IndexedDataMapOfShapeListOfShape aMapVE;
1112             
1113             for(i = 1; i <= mySection->NbLaw(); i++) {
1114               const TopoDS_Shape& aBottomEdge = aVEdges->Value(i, aVEdges->LowerCol());
1115
1116               if((!aBottomEdge.IsNull()) && (aBottomEdge.ShapeType() == TopAbs_EDGE)) {
1117                 TopExp::MapShapesAndAncestors(aBottomEdge, TopAbs_VERTEX, TopAbs_EDGE, aMapVE);
1118               }
1119             }
1120             const TopoDS_Shape& aFreeEdge = aUEdges->Value(eit, aUEdges->LowerCol());
1121             TopExp::MapShapesAndAncestors(aFreeEdge, TopAbs_VERTEX, TopAbs_EDGE, aMapVE);
1122             TopExp_Explorer anExpV(aFreeEdge, TopAbs_VERTEX);
1123
1124             for(; anExpV.More(); anExpV.Next()) {
1125               if(aMapVE.Contains(anExpV.Current())) {
1126                 const TopTools_ListOfShape& aListOfV = aMapVE.FindFromKey(anExpV.Current());
1127
1128                 if(aListOfV.Extent() >= 2) {
1129                   aGenVertex = anExpV.Current();
1130                 }
1131               }
1132             }
1133
1134             if(!aGenVertex.IsNull()) {
1135               UpdateMap(aGenVertex, aShape, myGenMap);
1136             }
1137           }
1138         }
1139       }
1140       // end for(eit = aUEdges->LowerRow...
1141     }
1142     // build history for free booundaries.end
1143   }
1144
1145   // build history for boundary section wires. begin
1146
1147   if(!mySeq.IsEmpty()) {
1148     Standard_Integer iseq;
1149     TopoDS_Wire aSect;
1150     Standard_Real param = 0., aparmin = RealLast(), aparmax = -RealLast();
1151     Standard_Integer ideb = 1, ifin = mySeq.Length();
1152
1153     for (iseq = 1;iseq <= mySeq.Length(); iseq++) {
1154       Place(mySeq(iseq), aSect, param);
1155
1156       if(param < aparmin) {
1157         ideb = iseq;
1158         aparmin = param;
1159       }
1160
1161       if(param > aparmax) {
1162         ifin = iseq;
1163         aparmax = param;
1164       }
1165     }
1166     
1167     UpdateMap(mySeq(ideb).Wire(), myFirst, myGenMap);
1168     UpdateMap(mySeq(ifin).Wire(), myLast, myGenMap);
1169   }
1170   // build history for boundary section wires. end
1171 }
1172
1173 // ---------------------------------------------------------------------------------
1174 // static function: UpdateMap
1175 // purpose:
1176 // ---------------------------------------------------------------------------------
1177 Standard_Boolean UpdateMap(const TopoDS_Shape&                 theKey,
1178                            const TopoDS_Shape&                 theValue,
1179                            TopTools_DataMapOfShapeListOfShape& theMap) {
1180
1181   if(!theMap.IsBound(theKey)) {
1182     TopTools_ListOfShape thelist;
1183     theMap.Bind(theKey, thelist);
1184   }
1185   TopTools_ListOfShape& aList = theMap.ChangeFind(theKey);
1186   TopTools_ListIteratorOfListOfShape anIt(aList);
1187   Standard_Boolean found = Standard_False;
1188
1189   for(; anIt.More(); anIt.Next()) {
1190     if(theValue.IsSame(anIt.Value())) {
1191       found = Standard_True;
1192       break;
1193     }
1194   }
1195
1196   if(!found)
1197     aList.Append(theValue);
1198   return !found;
1199 }
1200
1201 // ---------------------------------------------------------------------------------
1202 // static function: BuildBoundaries
1203 // purpose:
1204 // ---------------------------------------------------------------------------------
1205 Standard_Boolean BuildBoundaries(const BRepFill_Sweep&               theSweep,
1206                                  const Handle(BRepFill_SectionLaw)&  theSection,
1207                                  TopoDS_Shape&                       theBottom,
1208                                  TopoDS_Shape&                       theTop) {
1209   
1210   TopoDS_Wire aBottomWire;
1211   TopoDS_Wire aTopWire;
1212   BRep_Builder aB;
1213   aB.MakeWire(aBottomWire);
1214   aB.MakeWire(aTopWire);
1215   Standard_Boolean bfoundbottom = Standard_False;
1216   Standard_Boolean bfoundtop = Standard_False;
1217   Handle(TopTools_HArray2OfShape) aVEdges = theSweep.Sections();
1218   Standard_Integer i = 0;
1219   Standard_Boolean bAllSame = Standard_True;
1220
1221   for(i = 1; i <= theSection->NbLaw(); i++) {
1222     const TopoDS_Shape& aBottomEdge = aVEdges->Value(i, aVEdges->LowerCol());
1223
1224     if(!aBottomEdge.IsNull() && (aBottomEdge.ShapeType() == TopAbs_EDGE)) {
1225       aB.Add(aBottomWire, aBottomEdge);
1226       bfoundbottom = Standard_True;
1227     }
1228     const TopoDS_Shape& aTopEdge = aVEdges->Value(i, aVEdges->UpperCol());
1229
1230     if(!aTopEdge.IsNull() && (aTopEdge.ShapeType() == TopAbs_EDGE)) {
1231       aB.Add(aTopWire, aTopEdge);
1232       bfoundtop = Standard_True;
1233     }
1234
1235     if(!aBottomEdge.IsNull() && !aTopEdge.IsNull() && !aBottomEdge.IsSame(aTopEdge))
1236       bAllSame = Standard_False;
1237   }
1238
1239   if(theSection->IsUClosed()) {
1240     aBottomWire.Closed(Standard_True);
1241     aTopWire.Closed(Standard_True);
1242   }
1243
1244   if(bfoundbottom) {
1245     theBottom = aBottomWire;
1246   }
1247
1248   if(bfoundtop) {
1249     theTop  = aTopWire;
1250   }
1251
1252   if(bAllSame && bfoundbottom && bfoundtop)
1253     theTop = theBottom;
1254
1255   return bfoundbottom || bfoundtop;
1256 }