0030940: BRepFilletAPI_MakeFillet algorithm fails on closed shell
[occt.git] / src / ChFi3d / ChFi3d_Builder_1.cxx
1 // Created on: 1993-12-15
2 // Created by: Isabelle GRIGNON
3 // Copyright (c) 1993-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <Adaptor2d_HCurve2d.hxx>
19 #include <Adaptor3d_HSurface.hxx>
20 #include <Adaptor3d_TopolTool.hxx>
21 #include <AppBlend_Approx.hxx>
22 #include <Blend_CurvPointFuncInv.hxx>
23 #include <Blend_FuncInv.hxx>
24 #include <Blend_Function.hxx>
25 #include <Blend_RstRstFunction.hxx>
26 #include <Blend_SurfCurvFuncInv.hxx>
27 #include <Blend_SurfPointFuncInv.hxx>
28 #include <Blend_SurfRstFunction.hxx>
29 #include <BRep_Tool.hxx>
30 #include <BRepAdaptor_Curve.hxx>
31 #include <BRepAdaptor_HCurve2d.hxx>
32 #include <BRepAdaptor_HSurface.hxx>
33 #include <BRepAdaptor_Surface.hxx>
34 #include <BRepBlend_Line.hxx>
35 #include <BRepLProp_SLProps.hxx>
36 #include <BRepTopAdaptor_TopolTool.hxx>
37 #include <ChFi3d.hxx>
38 #include <ChFi3d_Builder.hxx>
39 #include <ChFi3d_Builder_0.hxx>
40 #include <ChFiDS_CommonPoint.hxx>
41 #include <ChFiDS_ErrorStatus.hxx>
42 #include <ChFiDS_FilSpine.hxx>
43 #include <ChFiDS_HData.hxx>
44 #include <ChFiDS_HElSpine.hxx>
45 #include <ChFiDS_ListIteratorOfListOfStripe.hxx>
46 #include <ChFiDS_ListIteratorOfRegularities.hxx>
47 #include <ChFiDS_Regul.hxx>
48 #include <ChFiDS_Spine.hxx>
49 #include <ChFiDS_State.hxx>
50 #include <ChFiDS_Stripe.hxx>
51 #include <ChFiDS_SurfData.hxx>
52 #include <Geom2d_Curve.hxx>
53 #include <Geom_Surface.hxx>
54 #include <Geom_OffsetSurface.hxx>
55 #include <Geom_RectangularTrimmedSurface.hxx>
56 #include <GeomInt_IntSS.hxx>
57 #include <Extrema_ExtPC.hxx>
58 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
59 #include <Geom_BSplineCurve.hxx>
60 #include <gp_Pnt.hxx>
61 #include <gp_Pnt2d.hxx>
62 #include <gp_Vec.hxx>
63 #include <LocalAnalysis_SurfaceContinuity.hxx>
64 #include <Precision.hxx>
65 #include <Standard_ConstructionError.hxx>
66 #include <Standard_NoSuchObject.hxx>
67 #include <Standard_OutOfRange.hxx>
68 #include <TopAbs.hxx>
69 #include <TopAbs_Orientation.hxx>
70 #include <TopAbs_ShapeEnum.hxx>
71 #include <TopExp.hxx>
72 #include <TopoDS.hxx>
73 #include <TopoDS_Edge.hxx>
74 #include <TopoDS_Face.hxx>
75 #include <TopoDS_Shape.hxx>
76 #include <TopoDS_Vertex.hxx>
77 #include <TopOpeBRepBuild_HBuilder.hxx>
78 #include <TopOpeBRepDS_HDataStructure.hxx>
79 #include <TopOpeBRepDS_Surface.hxx>
80 #include <TopOpeBRepTool_TOOL.hxx>
81 #include <TopTools_ListIteratorOfListOfShape.hxx>
82 #include <BRepLib_MakeEdge.hxx>
83
84 #ifdef OCCT_DEBUG
85 extern Standard_Boolean ChFi3d_GetcontextFORCEBLEND(); 
86 #endif
87
88 static void ReorderFaces(TopoDS_Face&         theF1,
89                          TopoDS_Face&         theF2,
90                          const TopoDS_Face&   theFirstFace,
91                          const TopoDS_Edge&   thePrevEdge,
92                          const TopoDS_Vertex& theCommonVertex)
93 {
94   if (theF1.IsSame(theFirstFace))
95     return;
96   else if (theF2.IsSame(theFirstFace))
97   {
98     TopoDS_Face TmpFace = theF1; theF1 = theF2; theF2 = TmpFace;
99     return;
100   }
101
102   TopTools_IndexedDataMapOfShapeListOfShape VEmapFirst, VEmap;
103   TopExp::MapShapesAndAncestors(theFirstFace, TopAbs_VERTEX, TopAbs_EDGE, VEmapFirst);
104   TopExp::MapShapesAndAncestors(theF1, TopAbs_VERTEX, TopAbs_EDGE, VEmap);
105
106   const TopTools_ListOfShape& ElistFirst = VEmapFirst.FindFromKey(theCommonVertex);
107   const TopTools_ListOfShape& Elist      = VEmap.FindFromKey(theCommonVertex);
108   TopTools_ListIteratorOfListOfShape itlfirst(ElistFirst);
109   for (; itlfirst.More(); itlfirst.Next())
110   {
111     const TopoDS_Shape& anEdge = itlfirst.Value();
112     if (anEdge.IsSame(thePrevEdge))
113       continue;
114     TopTools_ListIteratorOfListOfShape itl(Elist);
115     for(; itl.More(); itl.Next())
116       if (anEdge.IsSame(itl.Value()))
117         return;
118   }
119
120   TopoDS_Face TmpFace = theF1; theF1 = theF2; theF2 = TmpFace;
121 }
122
123 static void ConcatCurves(TColGeom_SequenceOfCurve& theCurves,
124                          TColGeom_SequenceOfCurve& theNewCurves)
125 {
126   while (!theCurves.IsEmpty())
127   {
128     GeomConvert_CompCurveToBSplineCurve Concat;
129     Standard_Boolean Success = Standard_False;
130     for (Standard_Integer i = 1; i <= theCurves.Length(); i++)
131     {
132       const Handle(Geom_Curve)& aCurve = theCurves(i);
133       Handle(Geom_BoundedCurve) aBoundedCurve = Handle(Geom_BoundedCurve)::DownCast(aCurve);
134       Success = Concat.Add(aBoundedCurve, 1.e-5, Standard_True);
135       if (!Success)
136         Success = Concat.Add(aBoundedCurve, 1.e-5, Standard_False);
137       if (Success)
138       {
139         theCurves.Remove(i);
140         i--;
141       }
142     }
143     Handle(Geom_Curve) aNewCurve = Concat.BSplineCurve();
144     theNewCurves.Append(aNewCurve);
145   }
146 }
147
148 static TopoDS_Edge MakeOffsetEdge(const TopoDS_Edge&         theEdge,
149                                   const Standard_Real        Distance,
150                                   const BRepAdaptor_Surface& S1,
151                                   const BRepAdaptor_Surface& S2)
152 {
153   TopoDS_Edge OffsetEdge;
154   
155   TopoDS_Face F1 = S1.Face();
156   TopoDS_Face F2 = S2.Face();
157   Handle(Geom_Surface) GS1 = BRep_Tool::Surface(F1);
158   Handle(Geom_Surface) TrGS1 =
159     new Geom_RectangularTrimmedSurface(GS1,
160                                        S1.FirstUParameter(), S1.LastUParameter(),
161                                        S1.FirstVParameter(), S1.LastVParameter());
162   Standard_Real Offset = -Distance;
163   if (F1.Orientation() == TopAbs_REVERSED)
164     Offset = Distance;
165   Handle(Geom_OffsetSurface) MakeOffsetSurf = new Geom_OffsetSurface(TrGS1, Offset);
166   Handle(Geom_Surface) OffsetTrGS1 = MakeOffsetSurf->Surface();
167   if (OffsetTrGS1.IsNull())
168     OffsetTrGS1 = MakeOffsetSurf;
169   Handle(Geom_Surface) GS2 = BRep_Tool::Surface(F2);
170   Handle(Geom_Surface) TrGS2 =
171     new Geom_RectangularTrimmedSurface(GS2,
172                                        S2.FirstUParameter(), S2.LastUParameter(),
173                                        S2.FirstVParameter(), S2.LastVParameter());
174   GeomInt_IntSS Intersector(OffsetTrGS1, TrGS2, Precision::Confusion());
175   if (!Intersector.IsDone() || Intersector.NbLines() == 0)
176   {
177     return OffsetEdge;
178   }
179
180   Handle(Geom_Curve) IntCurve = Intersector.Line(1);
181   gp_Pnt Ends [2];
182   BRepAdaptor_Curve aBAcurve(theEdge);
183   Ends[0] = aBAcurve.Value(aBAcurve.FirstParameter());
184   Ends[1] = aBAcurve.Value(aBAcurve.LastParameter());
185
186   if (Intersector.NbLines() > 1)
187   {
188     TColGeom_SequenceOfCurve Curves, NewCurves;
189     for (Standard_Integer i = 1; i <= Intersector.NbLines(); i++)
190       Curves.Append(Intersector.Line(i));
191
192     ConcatCurves(Curves, NewCurves);
193
194     Standard_Real MinDist = RealLast();
195     Standard_Integer imin = 1;
196     for (Standard_Integer i = 1; i <= NewCurves.Length(); i++)
197     {
198       GeomAdaptor_Curve GAcurve(NewCurves(i));
199       Extrema_ExtPC Projector(Ends[0], GAcurve);
200       if (!Projector.IsDone() || Projector.NbExt() == 0)
201         continue;
202       for (Standard_Integer iext = 1; iext <= Projector.NbExt(); iext++)
203       {
204         Standard_Real aDist = Projector.SquareDistance(iext);
205         if (aDist < MinDist)
206         {
207           MinDist = aDist;
208           imin = i;
209         }
210       }
211     }
212     IntCurve = NewCurves(imin);
213   }
214   if (IntCurve.IsNull())
215   {
216     return OffsetEdge;
217   }
218   //Projection of extremities onto <IntCurve>
219   GeomAdaptor_Curve GAcurve(IntCurve);
220   Standard_Real Params [2];
221   for (Standard_Integer ind_end = 0; ind_end < 2; ind_end++)
222   {
223     if (ind_end == 1 && aBAcurve.IsClosed()/*HGuide->IsPeriodic()*//*HGuide->IsClosed()*/)
224       break;
225     Extrema_ExtPC Projector(Ends[ind_end], GAcurve);
226     Standard_Real param[4], dist[4];
227     gp_Pnt Pnt[4];
228     param[1] = GAcurve.FirstParameter();
229     param[2] = GAcurve.LastParameter();
230     Projector.TrimmedSquareDistances(dist[1], dist[2], Pnt[1], Pnt[2]);
231     dist[3] = RealLast();
232     if (Projector.IsDone() && Projector.NbExt() > 0)
233     {
234       Standard_Integer imin = 1;
235       for (Standard_Integer i = 2; i <= Projector.NbExt(); i++)
236         if (Projector.SquareDistance(i) < Projector.SquareDistance(imin))
237           imin = i;
238       param[3] = Projector.Point(imin).Parameter();
239       dist[3]  = Projector.SquareDistance(imin);
240       Pnt[3]   = Projector.Point(imin).Value();
241     }
242
243     Standard_Integer imin = 1;
244     for (Standard_Integer i = 2; i <= 3; i++)
245       if (dist[i] < dist[imin])
246         imin = i;
247     
248     Params[ind_end] = param[imin]; //Projector.Point(imin).Parameter();
249   }
250   if (aBAcurve.IsClosed()/*HGuide->IsPeriodic()*//*HGuide->IsClosed()*/)
251     Params[1] = GAcurve.LastParameter(); //temporary
252   if (Params[0] > Params[1])
253   {
254     Standard_Boolean IsClosed = Standard_False;
255     gp_Pnt fpnt = IntCurve->Value(IntCurve->FirstParameter());
256     gp_Pnt lpnt = IntCurve->Value(IntCurve->LastParameter());
257     if (fpnt.SquareDistance(lpnt) <= Precision::SquareConfusion())
258       IsClosed = Standard_True;
259     if (IsClosed)
260       Params[1] = IntCurve->LastParameter();
261     else
262     {
263       Standard_Real NewFirstPar = IntCurve->ReversedParameter(Params[0]);
264       Standard_Real NewLastPar  = IntCurve->ReversedParameter(Params[1]);
265       IntCurve->Reverse();
266       Params[0] = NewFirstPar;
267       Params[1] = NewLastPar;
268     }
269   }
270   if (aBAcurve.IsClosed()/*HGuide->IsPeriodic()*//*HGuide->IsClosed()*/) //check the direction of closed curve
271   {
272     gp_Pnt aPnt, anOffsetPnt;
273     gp_Vec Tangent, OffsetTangent;
274     aBAcurve.D1(aBAcurve.FirstParameter(), aPnt, Tangent);
275     IntCurve->D1(Params[0], anOffsetPnt, OffsetTangent);
276     if (Tangent*OffsetTangent < 0)
277       IntCurve->Reverse();
278   }
279
280   /*
281   Standard_Real ParTol = 1.e-5;
282   Standard_Real FirstDiff = aBAcurve.FirstParameter() - Params[0];
283   Standard_Real LastDiff  = aBAcurve.LastParameter()  - Params[1];
284   if (Abs(FirstDiff) > ParTol ||
285       Abs(LastDiff)  > ParTol)
286   {
287     Handle(Geom_BSplineCurve) BsplCurve = Handle(Geom_BSplineCurve)::DownCast(IntCurve);
288     TColStd_Array1OfReal aKnots(1, BsplCurve->NbKnots());
289     BsplCurve->Knots(aKnots);
290     BSplCLib::Reparametrize(aBAcurve.FirstParameter(), aBAcurve.LastParameter(), aKnots);
291     BsplCurve->SetKnots(aKnots);
292     if (aBAcurve.IsPeriodic() && !BsplCurve->IsPeriodic())
293       BsplCurve->SetPeriodic();
294     IntCurve = BsplCurve;
295   }
296   */
297   
298   OffsetEdge = BRepLib_MakeEdge(IntCurve, Params[0], Params[1]);
299   return OffsetEdge;
300 }
301
302 static TopOpeBRepDS_BuildTool mkbuildtool()
303 {
304   TopOpeBRepTool_GeomTool GT2(TopOpeBRepTool_BSPLINE1,
305                               Standard_True,
306                               Standard_False,
307                               Standard_False);
308   TopOpeBRepDS_BuildTool BT(GT2);
309   BT.OverWrite(Standard_False);
310   BT.Translate(Standard_False);
311   return BT;
312 }
313
314 //=======================================================================
315 //function : ChFi3d_Builder
316 //purpose  : 
317 //=======================================================================
318 ChFi3d_Builder::ChFi3d_Builder(const TopoDS_Shape& S,
319                                const Standard_Real Ta) :  
320    done(Standard_False), myShape(S)
321 {
322   myDS = new TopOpeBRepDS_HDataStructure();
323   myCoup = new TopOpeBRepBuild_HBuilder(mkbuildtool());
324   myEFMap.Fill(S,TopAbs_EDGE,TopAbs_FACE);
325   myESoMap.Fill(S,TopAbs_EDGE,TopAbs_SOLID);
326   myEShMap.Fill(S,TopAbs_EDGE,TopAbs_SHELL);
327   myVFMap.Fill(S,TopAbs_VERTEX,TopAbs_FACE);
328   myVEMap.Fill(S,TopAbs_VERTEX,TopAbs_EDGE);
329   SetParams(Ta,1.e-4,1.e-5,1.e-4,1.e-5,1.e-3);
330   SetContinuity(GeomAbs_C1, Ta);
331 }
332
333 //=======================================================================
334 //function : SetParams
335 //purpose  : 
336 //=======================================================================
337
338 void ChFi3d_Builder::SetParams(const Standard_Real Tang, 
339                                const Standard_Real Tesp, 
340                                const Standard_Real T2d, 
341                                const Standard_Real TApp3d, 
342                                const Standard_Real TolApp2d, 
343                                const Standard_Real Fleche)
344 {
345   angular = Tang;
346   tolesp = Tesp;
347   tol2d =  T2d;
348   tolapp3d = TApp3d;
349   tolapp2d = TolApp2d;
350   fleche = Fleche;
351 }
352
353 //=======================================================================
354 //function : SetContinuity
355 //purpose  : 
356 //=======================================================================
357
358 void ChFi3d_Builder::SetContinuity(const GeomAbs_Shape InternalContinuity,
359                                    const Standard_Real AngularTolerance)
360 {
361   myConti = InternalContinuity;
362   tolappangle = AngularTolerance;
363 }
364
365 //=======================================================================
366 //function : IsDone
367 //purpose  : 
368 //=======================================================================
369
370 Standard_Boolean ChFi3d_Builder::IsDone() const 
371 {
372   return done;
373 }
374
375 //=======================================================================
376 //function : Shape
377 //purpose  : 
378 //=======================================================================
379
380 TopoDS_Shape ChFi3d_Builder::Shape()const
381 {
382   Standard_NoSuchObject_Raise_if (!done, "ChFi3d_Builder::Shape() - no result");
383   return myShapeResult;
384 }
385
386 //=======================================================================
387 //function : NbFaultyContours
388 //purpose  : 
389 //=======================================================================
390
391 Standard_Integer ChFi3d_Builder::NbFaultyContours() const
392 {
393   return badstripes.Extent();
394 }
395
396 //=======================================================================
397 //function : FaultyContour
398 //purpose  : 
399 //=======================================================================
400
401 Standard_Integer ChFi3d_Builder::FaultyContour(const Standard_Integer I) const
402 {
403   ChFiDS_ListIteratorOfListOfStripe itel;
404   Standard_Integer k = 0;
405   Handle(ChFiDS_Stripe) st;
406   for (itel.Initialize(badstripes);itel.More(); itel.Next()) {
407     k += 1;
408     if(k == I) {
409       st = itel.Value();
410       break;
411     }
412   }
413   if(st.IsNull()) return 0;
414   k = 0;
415   for (itel.Initialize(myListStripe);itel.More(); itel.Next()) {
416     k += 1;
417     if(st == itel.Value()) return k;
418   }
419   return 0;
420 }
421
422 //=======================================================================
423 //function : NbComputedSurfaces
424 //purpose  : 
425 //=======================================================================
426
427 Standard_Integer ChFi3d_Builder::NbComputedSurfaces(const Standard_Integer IC) const
428 {
429   ChFiDS_ListIteratorOfListOfStripe itel;
430   Standard_Integer k = 0;
431   Handle(ChFiDS_Stripe) st;
432   for (itel.Initialize(myListStripe);itel.More(); itel.Next()) {
433     k += 1;
434     if(k == IC) {
435       st = itel.Value();
436       break;
437     }
438   }
439   if(st.IsNull()) return 0;
440   if(st->Spine().IsNull()) return 0;
441   Handle(ChFiDS_HData) hd = st->SetOfSurfData();
442   if(hd.IsNull()) return 0;
443   return hd->Length();
444 }
445
446 //=======================================================================
447 //function : ComputedSurface
448 //purpose  : 
449 //=======================================================================
450
451 Handle(Geom_Surface) ChFi3d_Builder::ComputedSurface(const Standard_Integer IC,
452                                                      const Standard_Integer IS) const
453 {
454  ChFiDS_ListIteratorOfListOfStripe itel;
455   Standard_Integer k = 0;
456   Handle(ChFiDS_Stripe) st;
457   for (itel.Initialize(myListStripe);itel.More(); itel.Next()) {
458     k += 1;
459     if(k == IC) {
460       st = itel.Value();
461       break;
462     }
463   }
464   Handle(ChFiDS_HData) hd = st->SetOfSurfData();
465   Standard_Integer isurf=hd->Value(IS)->Surf();
466   return  myDS->Surface(isurf).Surface();
467 }
468
469 //=======================================================================
470 //function : NbFaultyVertices
471 //purpose  : 
472 //=======================================================================
473
474 Standard_Integer ChFi3d_Builder::NbFaultyVertices() const
475 {
476   return badvertices.Extent();
477 }
478
479 //=======================================================================
480 //function : FaultyVertex
481 //purpose  : 
482 //=======================================================================
483
484 TopoDS_Vertex ChFi3d_Builder::FaultyVertex(const Standard_Integer IV) const
485 {
486   TopTools_ListIteratorOfListOfShape it;
487   TopoDS_Vertex V;
488   Standard_Integer k = 0;
489   for(it.Initialize(badvertices);it.More(); it.Next()) {
490     k += 1;
491     if(k == IV) {
492       V = TopoDS::Vertex(it.Value());
493       break;
494     }
495   }
496   return V;
497 }
498
499 //=======================================================================
500 //function : HasResult
501 //purpose  : 
502 //=======================================================================
503
504 Standard_Boolean ChFi3d_Builder::HasResult() const 
505 {
506   return hasresult;
507 }
508
509 //=======================================================================
510 //function : BadShape
511 //purpose  : 
512 //=======================================================================
513
514 TopoDS_Shape ChFi3d_Builder::BadShape()const
515 {
516   Standard_NoSuchObject_Raise_if (!hasresult, "ChFi3d_Builder::BadShape() - no result");
517   return badShape;
518 }
519
520 //=======================================================================
521 //function : StripeStatus
522 //purpose  : 
523 //=======================================================================
524
525 ChFiDS_ErrorStatus ChFi3d_Builder::StripeStatus(const Standard_Integer IC)const
526 {  
527   ChFiDS_ListIteratorOfListOfStripe itel;
528   Standard_Integer k =0;
529   Handle(ChFiDS_Stripe) st;
530   for (itel.Initialize(myListStripe);itel.More(); itel.Next()) {
531     k += 1;
532     if(k == IC) {
533       st = itel.Value();
534       break;
535     }
536   }
537   ChFiDS_ErrorStatus stat=st->Spine()->ErrorStatus();
538   return stat;
539 }
540
541 //=======================================================================
542 //function : Builder
543 //purpose  : 
544 //=======================================================================
545
546 Handle(TopOpeBRepBuild_HBuilder) ChFi3d_Builder::Builder()const
547 {
548   return myCoup;
549 }
550
551 //=======================================================================
552 //function : ChFi3d_FaceTangency
553 //purpose  : determine if the faces opposing to edges are tangent
554 //           to go from opposing faces on e0 to opposing faces 
555 //           on e1, consider all faces starting at a common top.
556 //=======================================================================
557
558 Standard_Boolean ChFi3d_Builder::FaceTangency(const TopoDS_Edge& E0,
559                                               const TopoDS_Edge& E1,
560                                               const TopoDS_Vertex& V) const
561 {
562   TopTools_ListIteratorOfListOfShape It,Jt;
563   TopoDS_Edge Ec;
564   Standard_Integer Nbf;
565   TopoDS_Face F[2];
566
567   //It is checked if the connection is not on a regular edge.
568   for (It.Initialize(myEFMap(E1)), Nbf= 0 ;It.More();It.Next(), Nbf++) {
569     if (Nbf>1) 
570       throw Standard_ConstructionError("ChFi3d_Builder:only 2 faces");
571     F[Nbf] = TopoDS::Face(It.Value());
572   }      
573   if(Nbf < 2) return Standard_False;
574 //  Modified by Sergey KHROMOV - Fri Dec 21 17:44:19 2001 Begin
575 //if (BRep_Tool::Continuity(E1,F[0],F[1]) != GeomAbs_C0) {
576   if (ChFi3d_isTangentFaces(E1,F[0],F[1])) {
577 //  Modified by Sergey KHROMOV - Fri Dec 21 17:44:21 2001 End
578     return Standard_False;
579   }
580
581   for (Jt.Initialize(myVEMap(V));Jt.More();Jt.Next()) {
582     Ec = TopoDS::Edge(Jt.Value());
583     if (!Ec.IsSame(E0) && !Ec.IsSame(E1) && 
584         Ec.Orientation() != TopAbs_INTERNAL && 
585         Ec.Orientation() != TopAbs_EXTERNAL &&
586         !BRep_Tool::Degenerated(Ec)) {
587       for (It.Initialize(myEFMap(Ec)), Nbf= 0 ;It.More();It.Next(), Nbf++) {
588         if (Nbf>1) 
589           throw Standard_ConstructionError("ChFi3d_Builder:only 2 faces");
590         F[Nbf] = TopoDS::Face(It.Value());
591       }      
592       if(Nbf < 2) return Standard_False;
593 //  Modified by Sergey KHROMOV - Tue Dec 18 18:10:40 2001 Begin
594 //    if (BRep_Tool::Continuity(Ec,F[0],F[1]) < GeomAbs_G1) {
595       if (!ChFi3d_isTangentFaces(Ec,F[0],F[1])) {
596 //  Modified by Sergey KHROMOV - Tue Dec 18 18:10:41 2001 End
597         return Standard_False;
598       }
599     }
600   }
601   return Standard_True;
602   
603 }
604
605
606 //=======================================================================
607 //function : TangentExtremity
608 //purpose  : Test if 2 faces are tangent at the end of an edge
609 //=======================================================================
610 static Standard_Boolean TangentExtremity(const TopoDS_Vertex&                V,
611                                          const TopoDS_Edge&                  E,
612                                          const Handle(BRepAdaptor_HSurface)& hs1,
613                                          const Handle(BRepAdaptor_HSurface)& hs2,
614 //                                       const Standard_Real                 t3d,
615                                          const Standard_Real                 tang)
616 {
617   TopoDS_Face f1 = hs1->ChangeSurface().Face();
618   TopAbs_Orientation O1 = f1.Orientation();
619   f1.Orientation(TopAbs_FORWARD);
620   TopoDS_Face f2 = hs2->ChangeSurface().Face();
621   TopAbs_Orientation O2 = f2.Orientation();
622   f2.Orientation(TopAbs_FORWARD);
623   TopoDS_Edge e1 = E, e2 = E;
624   e1.Orientation(TopAbs_FORWARD);
625   e2.Orientation(TopAbs_FORWARD);
626   if(f1.IsSame(f2) && BRep_Tool::IsClosed(e1,f1))
627     e2.Orientation(TopAbs_REVERSED);
628   Standard_Real p1 = BRep_Tool::Parameter(V,e1,f1);
629   Standard_Real p2 = BRep_Tool::Parameter(V,e2,f2);
630   Standard_Real u,v,f,l, Eps = 1.e-9;
631   gp_Vec n1, n2;//   gp_Pnt pt1,pt2;
632   Handle(Geom2d_Curve) pc1 = BRep_Tool::CurveOnSurface(e1,f1,f,l);
633   pc1->Value(p1).Coord(u,v);
634   BRepLProp_SLProps theProp1(hs1->ChangeSurface(), u, v, 1, Eps);
635   if  (theProp1.IsNormalDefined()) {
636     n1.SetXYZ(theProp1.Normal().XYZ());
637     if (O1 == TopAbs_REVERSED) n1.Reverse();
638   }
639   else return Standard_False; // It is not known...
640
641  
642   Handle(Geom2d_Curve) pc2 = BRep_Tool::CurveOnSurface(e2,f2,f,l);
643   pc2->Value(p2).Coord(u,v);
644   BRepLProp_SLProps theProp2(hs2->ChangeSurface(), u, v, 1, Eps);
645   if  (theProp2.IsNormalDefined()) {
646     n2.SetXYZ(theProp2.Normal().XYZ());
647     if(O2 == TopAbs_REVERSED) n2.Reverse();
648   }
649   else return Standard_False; //  It is not known...
650
651   return (n1.Angle(n2) < tang);
652 }
653
654 //=======================================================================
655 //function : TangentOnVertex
656 //purpose  : Test if support faces of an edge are tangent at end.
657 //=======================================================================
658 static Standard_Boolean TangentOnVertex(const TopoDS_Vertex&    V,
659                                         const TopoDS_Edge&      E,
660                                         const ChFiDS_Map&       EFMap,
661                                         const Standard_Real     tang)
662 {
663   TopoDS_Face ff1,ff2;
664   ChFi3d_conexfaces(E,ff1,ff2,EFMap);
665   if(ff1.IsNull() || ff2.IsNull()) return 0;
666   Handle(BRepAdaptor_HSurface) S1 = new (BRepAdaptor_HSurface)(ff1);
667   Handle(BRepAdaptor_HSurface) S2 = new (BRepAdaptor_HSurface)(ff2);
668   return TangentExtremity(V, E, S1, S2, tang);
669 }
670
671 //=======================================================================
672 //function : PerformExtremity
673 //purpose  : In case if PerformElement returned BreakPoint at one or  
674 //           another extremity, it is attempted to refine 
675 //           depending on concavities between neighbour faces of the top.
676 //=======================================================================
677
678 void ChFi3d_Builder::PerformExtremity (const Handle(ChFiDS_Spine)& Spine) 
679 {
680   Standard_Integer NbG1Connections = 0;
681   
682   for(Standard_Integer ii = 1; ii <= 2; ii++){
683     TopoDS_Edge E[3];
684     TopoDS_Vertex V;
685     ChFiDS_State sst;
686     Standard_Integer iedge;
687     Handle(BRepAdaptor_HSurface) hs1,hs2;
688     if(ii == 1){
689       sst = Spine->FirstStatus();
690       iedge = 1;
691       V = Spine->FirstVertex();
692     }
693     else{
694       sst = Spine->LastStatus(); 
695       iedge = Spine->NbEdges();
696       E[0] = Spine->Edges(iedge);
697       V = Spine->LastVertex();
698     }
699     //Before all it is checked if the tangency is not dead.
700     E[0] = Spine->Edges(iedge);
701     ConexFaces (Spine,iedge,hs1,hs2);
702     if(TangentExtremity(V,E[0],hs1,hs2,angular)){
703       Spine->SetTangencyExtremity(Standard_True, (ii == 1));
704     }
705
706     if(sst == ChFiDS_BreakPoint){
707       TopTools_ListIteratorOfListOfShape It;//,Jt;
708       Standard_Boolean sommetpourri = Standard_False;
709       TopTools_IndexedMapOfOrientedShape EdgesOfV;
710       TopTools_MapOfShape Edges;
711       Edges.Add(E[0]);
712       EdgesOfV.Add(E[0]);
713       Standard_Integer IndOfE = 0;
714       for (It.Initialize(myVEMap(V)); It.More(); It.Next())
715       {
716         TopoDS_Edge anEdge = TopoDS::Edge(It.Value());
717         if (BRep_Tool::Degenerated(anEdge))
718           continue;
719         TopoDS_Face F1, F2;
720         ChFi3d_conexfaces(anEdge, F1, F2, myEFMap);
721         if (!F2.IsNull() && ChFi3d_isTangentFaces(anEdge, F1, F2, GeomAbs_G2)) //smooth edge
722         {
723           if (!F1.IsSame(F2))
724             NbG1Connections++;
725           continue;
726         }
727         
728         if (Edges.Add(anEdge))
729         {
730           EdgesOfV.Add(anEdge);
731           if (IndOfE < 2)
732           {
733             IndOfE++;
734             E[IndOfE] = anEdge;
735           }
736         }
737         else
738         {
739           TopoDS_Vertex V1, V2;
740           TopExp::Vertices(anEdge, V1, V2);
741           if (V1.IsSame(V2)) //edge is closed - two ends of the edge in the vertex
742           {
743             Standard_Integer anInd = EdgesOfV.FindIndex(anEdge);
744             if (anInd == 0)
745               anInd = EdgesOfV.FindIndex(anEdge.Reversed());
746             anEdge = TopoDS::Edge(EdgesOfV(anInd));
747             anEdge.Reverse();
748             if (EdgesOfV.Add(anEdge))
749             {
750               if (IndOfE < 2)
751               {
752                 IndOfE++;
753                 E[IndOfE] = anEdge;
754               }
755             }
756           }
757         }
758       }
759       
760       if (EdgesOfV.Extent() != 3)
761         sommetpourri = Standard_True;
762       
763       if(!sommetpourri){
764         sst = ChFi3d_EdgeState(E,myEFMap);
765       }
766       if(ii==1)Spine->SetFirstStatus(sst);
767       else Spine->SetLastStatus(sst);
768     }
769   }
770   
771   if (!Spine->IsPeriodic()) {
772     TopTools_ListIteratorOfListOfShape It,Jt;
773     Standard_Integer nbf = 0, jf = 0;
774     for (It.Initialize(myVFMap(Spine->FirstVertex())); It.More(); It.Next()){
775       jf++;
776       Standard_Integer kf = 1;
777       const TopoDS_Shape& cur = It.Value();
778       for (Jt.Initialize(myVFMap(Spine->FirstVertex())); Jt.More() && (kf < jf); Jt.Next(), kf++){
779         if(cur.IsSame(Jt.Value())) break;
780       }
781       if(kf == jf) nbf++;
782     }
783     nbf -= NbG1Connections;
784     if(nbf>3) {
785       Spine->SetFirstStatus(ChFiDS_BreakPoint);
786 #ifdef OCCT_DEBUG
787       std::cout<<"top has : "<<nbf<<" faces."<<std::endl;
788 #endif
789     }
790     nbf = 0, jf = 0;
791     for (It.Initialize(myVFMap(Spine->LastVertex())); It.More(); It.Next()){
792       jf++;
793       Standard_Integer kf = 1;
794       const TopoDS_Shape& cur = It.Value();
795       for (Jt.Initialize(myVFMap(Spine->LastVertex())); Jt.More() && (kf < jf); Jt.Next(), kf++){
796         if(cur.IsSame(Jt.Value())) break;
797       }
798       if(kf == jf) nbf++;
799     }
800     nbf -= NbG1Connections;
801     if(nbf>3) {
802       Spine->SetLastStatus(ChFiDS_BreakPoint);
803 #ifdef OCCT_DEBUG
804       std::cout<<"top has : "<<nbf<<" faces."<<std::endl;
805 #endif
806     }
807   }
808 }
809
810 //=======================================================================
811 //function : PerformElement
812 //purpose  :  find all mutually tangent edges ;
813 // Each edge has 2 opposing faces. For 2 adjacent tangent edges it is required that 
814 // the opposing faces were tangent.
815 //=======================================================================
816
817 Standard_Boolean ChFi3d_Builder::PerformElement(const Handle(ChFiDS_Spine)& Spine,
818                                                 const Standard_Real         Offset,
819                                                 const TopoDS_Face&          theFirstFace)
820 {
821   Standard_Real ta = angular;
822   TopTools_ListIteratorOfListOfShape It;
823   Standard_Integer Nbface;
824   TopTools_ListIteratorOfListOfShape Jt;
825   Standard_Real Wl,Wf;
826   Standard_Boolean degeneOnEc;
827   gp_Pnt P2;
828   gp_Vec V1,V2;
829   TopoDS_Vertex Ve1,VStart,FVEc,LVEc,FVEv,LVEv;
830   TopoDS_Edge Ev,Ec(Spine->Edges(1));
831   if(BRep_Tool::Degenerated(Ec)) return 0;
832   //it is checked if the edge is a cut edge
833   TopoDS_Face ff1,ff2;
834   ChFi3d_conexfaces(Ec,ff1,ff2,myEFMap);
835   if(ff1.IsNull() || ff2.IsNull()) return 0;
836 //  Modified by Sergey KHROMOV - Fri Dec 21 17:46:22 2001 End
837 //if(BRep_Tool::Continuity(Ec,ff1,ff2) != GeomAbs_C0) return 0;
838   if (ChFi3d_isTangentFaces(Ec,ff1,ff2)) return 0;
839 //  Modified by Sergey KHROMOV - Fri Dec 21 17:46:24 2001 Begin
840
841   TopoDS_Face FirstFace = ff1;
842   if (!theFirstFace.IsNull() && ff2.IsSame(theFirstFace))
843   {
844     FirstFace = ff2;
845     ff2 = ff1; ff1 = FirstFace;
846   }
847   myEdgeFirstFace.Bind(Ec, FirstFace);
848
849   //Define concavity
850   ChFiDS_TypeOfConcavity TypeOfConcavity = ChFi3d::DefineConnectType(Ec, ff1, ff2,
851                                                                      1.e-5, Standard_True);
852   Spine->SetTypeOfConcavity(TypeOfConcavity);
853   
854   Standard_Boolean ToRestrict = (Offset > 0)? Standard_True : Standard_False;
855   BRepAdaptor_Surface Sb1(ff1, ToRestrict);
856   BRepAdaptor_Surface Sb2(ff2, ToRestrict);
857   if (Offset > 0)
858   {
859     TopoDS_Edge OffsetEdge = MakeOffsetEdge(Ec, Offset, Sb1, Sb2);
860     OffsetEdge.Orientation(Ec.Orientation());
861     Spine->SetOffsetEdges(OffsetEdge);
862   }
863   
864   BRepAdaptor_Curve CEc,CEv;
865   TopAbs_Orientation curor = Ec.Orientation();
866   TopExp::Vertices(Ec,VStart,LVEc);
867
868
869   Standard_Boolean Fini = Standard_False;
870   Standard_Integer Nb;
871   ChFiDS_State CurSt = ChFiDS_Closed;
872   if (VStart.IsSame(LVEc)) {//case if only one edge is closed
873     CEc.Initialize(Ec);
874     Wl = BRep_Tool::Parameter(VStart,Ec);
875     CEc.D1(Wl,P2,V1);
876     Wl = BRep_Tool::Parameter(LVEc,Ec);
877     CEc.D1(Wl,P2,V2);
878     Standard_Boolean IsFaceTangency = FaceTangency(Ec,Ec,VStart);
879     if (V1.IsParallel(V2,ta) ||
880         IsFaceTangency)
881     {
882       if (IsFaceTangency) {
883         CurSt = ChFiDS_Closed; 
884       }
885       else {
886         CurSt = ChFiDS_BreakPoint; 
887       } 
888     }
889     else {
890       CurSt = ChFiDS_BreakPoint; 
891     }
892     Spine->SetLastStatus(CurSt);
893     Spine->SetFirstStatus(CurSt);
894   }
895   else { // Downstream progression
896     FVEc = VStart;
897     TopAbs_Orientation Or1;
898     while (!Fini) {
899       CurSt = ChFiDS_FreeBoundary;
900       Wl = BRep_Tool::Parameter(LVEc,Ec);
901       degeneOnEc = TangentOnVertex(LVEc, Ec, myEFMap, ta);
902       CEc.Initialize(Ec);
903       CEc.D1(Wl,P2,V1);
904       Nb = Spine->NbEdges();
905
906       for (It.Initialize(myVEMap(LVEc));It.More();It.Next()) {
907         Ev = TopoDS::Edge(It.Value());
908         if (!Ev.IsSame(Ec) && !BRep_Tool::Degenerated(Ev)){
909           TopExp::Vertices(Ev,FVEv,LVEv);
910           if (LVEc.IsSame(LVEv)) {
911             Ve1 = FVEv;
912             FVEv = LVEv;
913             LVEv = Ve1;
914             Or1 = TopAbs_REVERSED;
915           }
916           else Or1 = TopAbs_FORWARD;
917
918           Wf = BRep_Tool::Parameter(FVEv,Ev);
919           CEv.Initialize(Ev);
920           CEv.D1(Wf,P2,V2);   
921           Standard_Real av1v2 = V1.Angle(V2);
922           Standard_Boolean rev = (Or1 != curor);    
923           Standard_Boolean OnAjoute = Standard_False;
924           if (FaceTangency(Ec,Ev,FVEv)) {
925             // there is no need of tolerance
926             // to make a decision (PRO9486) the regularity is enough.
927             // However, the abcense of turn-back is checked (PRO9810)
928             OnAjoute = ((!rev && av1v2 < M_PI/2) 
929                         ||(rev && av1v2 > M_PI/2));
930             // mate attention to the single case (cf CTS21610_1)
931             if (OnAjoute && (degeneOnEc || 
932                 TangentOnVertex(LVEc, Ev,myEFMap, ta)) )
933               OnAjoute=((!rev && av1v2 < ta) || (rev && (M_PI - av1v2) < ta));
934           }
935           if (OnAjoute) {
936             Fini = Standard_False; // If this can be useful (Cf PRO14713)
937             TopoDS_Vertex CommonVertex;
938             TopExp::CommonVertex(Ec, Ev, CommonVertex);
939             TopoDS_Edge PrevEdge = Ec;
940             Ec = Ev; 
941 //          Ec = TopoDS::Edge(Ev); 
942             Ec.Orientation(Or1);
943             Wl = Wf; LVEc = LVEv; 
944             Spine->SetEdges(Ec);
945             TopoDS_Face CurF1, CurF2;
946             ChFi3d_conexfaces(Ec,CurF1,CurF2,myEFMap);
947             ReorderFaces(CurF1, CurF2, FirstFace, PrevEdge, CommonVertex);
948             myEdgeFirstFace.Bind(Ec, CurF1);
949             if (Offset > 0)
950             {
951               BRepAdaptor_Surface CurSb1(CurF1), CurSb2(CurF2);
952               TopoDS_Edge anOffsetEdge = MakeOffsetEdge(Ec, Offset, CurSb1, CurSb2);
953               anOffsetEdge.Orientation(Or1);
954               Spine->SetOffsetEdges(anOffsetEdge);
955             }
956             FirstFace = CurF1;
957             curor = Or1;
958             if (VStart.IsSame(LVEv)) {
959               if (FaceTangency(Ev,Spine->Edges(1),LVEv)) {
960                 CurSt = ChFiDS_Closed; Fini = Standard_True;
961               }
962               else {
963                 CurSt = ChFiDS_BreakPoint;Fini = Standard_True;
964               }
965             }
966             break;
967           }
968           else {
969             for (Jt.Initialize(myEFMap(Ev)), Nbface= 0 ;Jt.More();Jt.Next(), 
970                  Nbface++) {}
971             if (Nbface> 1) CurSt = ChFiDS_BreakPoint;
972             Fini = ((!rev && av1v2 < ta) || (rev && (M_PI - av1v2) < ta)); 
973           }
974         } 
975       } 
976       Fini = Fini || (Nb == Spine->NbEdges());
977     }
978     Spine->SetLastStatus(CurSt);
979     if (CurSt == ChFiDS_Closed) {
980       Spine->SetFirstStatus(CurSt);
981     }
982     else {// Upstream progression
983       Fini = Standard_False;
984       Ec = Spine->Edges(1);
985       FirstFace = TopoDS::Face(myEdgeFirstFace(Ec));
986       curor = Ec.Orientation();
987       FVEc = VStart;
988       while (!Fini) {
989         CurSt = ChFiDS_FreeBoundary;
990         Wl = BRep_Tool::Parameter(FVEc,Ec);
991         degeneOnEc = TangentOnVertex(FVEc, Ec, myEFMap, ta);
992         CEc.Initialize(Ec);
993         CEc.D1(Wl,P2,V1);
994         Nb = Spine->NbEdges();
995
996         for (It.Initialize(myVEMap(FVEc));It.More();It.Next()) {
997           Ev = TopoDS::Edge(It.Value());
998           if (!Ev.IsSame(Ec) && !BRep_Tool::Degenerated(Ev)) {
999             TopExp::Vertices(Ev,FVEv,LVEv);
1000             if (FVEc.IsSame(FVEv)) {
1001               Ve1 = FVEv;
1002               FVEv = LVEv;
1003               LVEv = Ve1;
1004               Or1 = TopAbs_REVERSED;
1005             }
1006             else {
1007               Or1 = TopAbs_FORWARD;
1008             }
1009             Wf = BRep_Tool::Parameter(LVEv,Ev);
1010             CEv.Initialize(Ev);
1011             CEv.D1(Wf,P2,V2);
1012             Standard_Real av1v2 = V1.Angle(V2);
1013             Standard_Boolean rev = (Or1 != curor);
1014             Standard_Boolean OnAjoute =  Standard_False;
1015             if (FaceTangency(Ec,Ev,LVEv)) {
1016               OnAjoute = ((!rev && av1v2 < M_PI/2) 
1017                         ||(rev && av1v2 > M_PI/2));
1018             if (OnAjoute && (degeneOnEc || 
1019                 TangentOnVertex(FVEc, Ev,myEFMap, ta)) )
1020               OnAjoute=((!rev && av1v2 < ta) || (rev && (M_PI-av1v2) < ta));
1021             }
1022             if  (OnAjoute) {
1023               TopoDS_Vertex CommonVertex;
1024               TopExp::CommonVertex(Ec, Ev, CommonVertex);
1025               TopoDS_Edge PrevEdge = Ec;
1026               Ec = Ev; 
1027 //            Ec = TopoDS::Edge(Ev); 
1028               Ec.Orientation(Or1);
1029               Wl = Wf; FVEc = FVEv; 
1030               Spine->PutInFirst(Ec);
1031               TopoDS_Face CurF1, CurF2;
1032               ChFi3d_conexfaces(Ec,CurF1,CurF2,myEFMap);
1033               ReorderFaces(CurF1, CurF2, FirstFace, PrevEdge, CommonVertex);
1034               myEdgeFirstFace.Bind(Ec, CurF1);
1035               if (Offset > 0)
1036               {
1037                 BRepAdaptor_Surface CurSb1(CurF1), CurSb2(CurF2);
1038                 TopoDS_Edge anOffsetEdge = MakeOffsetEdge(Ec, Offset, CurSb1, CurSb2);
1039                 anOffsetEdge.Orientation(Or1);
1040                 Spine->PutInFirstOffset(anOffsetEdge);
1041               }
1042               FirstFace = CurF1;
1043               curor = Or1;
1044               break;
1045             }
1046             else {
1047               for(Jt.Initialize(myEFMap(Ev)),Nbface= 0 ;Jt.More();Jt.Next(), 
1048                   Nbface++) {}
1049               if (Nbface> 1) CurSt = ChFiDS_BreakPoint;
1050               Fini = ((!rev && av1v2 < ta) || (rev && (M_PI - av1v2) < ta));
1051             }
1052           } 
1053         } 
1054         Fini = Fini || (Nb == Spine->NbEdges());
1055       }
1056       Spine->SetFirstStatus(CurSt);
1057     }
1058   }
1059   return 1;
1060 }
1061
1062 //=======================================================================
1063 //function : Remove
1064 //purpose  : 
1065 //=======================================================================
1066
1067 void  ChFi3d_Builder::Remove(const TopoDS_Edge& E)
1068 {
1069   ChFiDS_ListIteratorOfListOfStripe itel(myListStripe);
1070
1071   for ( ; itel.More(); itel.Next()) {
1072     const Handle(ChFiDS_Spine)& sp = itel.Value()->Spine();
1073     for (Standard_Integer j = 1; j <= sp->NbEdges(); j++){
1074       if (E.IsSame(sp->Edges(j))){
1075         myListStripe.Remove(itel);
1076         return;
1077       }
1078     }
1079   }
1080 }
1081
1082
1083 //=======================================================================
1084 //function : Value
1085 //purpose  : 
1086 //=======================================================================
1087
1088 Handle(ChFiDS_Spine) ChFi3d_Builder::Value
1089 (const Standard_Integer I)const 
1090 {
1091   ChFiDS_ListIteratorOfListOfStripe itel(myListStripe);
1092   for (Standard_Integer ic = 1; ic < I; ic++) {itel.Next();}
1093   return itel.Value()->Spine();
1094 }
1095
1096 //=======================================================================
1097 //function : NbElements
1098 //purpose  : 
1099 //=======================================================================
1100
1101 Standard_Integer ChFi3d_Builder::NbElements()const 
1102 {
1103   Standard_Integer i = 0;
1104   ChFiDS_ListIteratorOfListOfStripe itel(myListStripe);
1105   for ( ;itel.More(); itel.Next()){
1106     const Handle(ChFiDS_Spine)& sp = itel.Value()->Spine();
1107     if(sp.IsNull()) break;
1108     i++;
1109   }
1110   return i;
1111 }
1112
1113 //=======================================================================
1114 //function : Contains
1115 //purpose  : 
1116 //=======================================================================
1117
1118 Standard_Integer ChFi3d_Builder::Contains(const TopoDS_Edge& E)const
1119 {
1120   Standard_Integer i = 1,j;
1121   ChFiDS_ListIteratorOfListOfStripe itel(myListStripe);
1122   for ( ;itel.More(); itel.Next(), i++){
1123     const Handle(ChFiDS_Spine)& sp = itel.Value()->Spine();
1124     if(sp.IsNull()) break;
1125     for (j = 1; j <= sp->NbEdges(); j++){
1126       if(E.IsSame(sp->Edges(j))) return i;
1127     }
1128   }
1129   return 0;
1130 }
1131
1132 //=======================================================================
1133 //function : Contains
1134 //purpose  : 
1135 //=======================================================================
1136
1137 Standard_Integer ChFi3d_Builder::Contains(const TopoDS_Edge& E,
1138                                           Standard_Integer&  IndexInSpine)const
1139 {
1140   Standard_Integer i = 1,j;
1141   IndexInSpine = 0;
1142   ChFiDS_ListIteratorOfListOfStripe itel(myListStripe);
1143   for ( ;itel.More(); itel.Next(), i++){
1144     const Handle(ChFiDS_Spine)& sp = itel.Value()->Spine();
1145     if(sp.IsNull()) break;
1146     for (j = 1; j <= sp->NbEdges(); j++){
1147       if(E.IsSame(sp->Edges(j)))
1148         {
1149           IndexInSpine = j;
1150           return i;
1151         }
1152     }
1153   }
1154   return 0;
1155 }
1156
1157 //=======================================================================
1158 //function : Length
1159 //purpose  : 
1160 //=======================================================================
1161
1162 Standard_Real ChFi3d_Builder::Length(const Standard_Integer IC)const
1163 {
1164   if(IC <= NbElements()){
1165     const Handle(ChFiDS_Spine)& sp = Value(IC);
1166     return sp->LastParameter(sp->NbEdges());
1167   }
1168   return -1;
1169 }
1170
1171
1172 //=======================================================================
1173 //function : FirstVertex
1174 //purpose  : 
1175 //=======================================================================
1176
1177 TopoDS_Vertex ChFi3d_Builder::FirstVertex(const Standard_Integer IC) const
1178 {
1179   if(IC <= NbElements()){
1180     return Value(IC)->FirstVertex();
1181   }
1182   return TopoDS_Vertex();
1183 }
1184
1185 //=======================================================================
1186 //function : LastVertex
1187 //purpose  : 
1188 //=======================================================================
1189
1190 TopoDS_Vertex ChFi3d_Builder::LastVertex(const Standard_Integer IC) const
1191 {
1192   if(IC <= NbElements()){
1193     return Value(IC)->LastVertex();
1194   }
1195   return TopoDS_Vertex();
1196 }
1197
1198 //=======================================================================
1199 //function : Abscissa
1200 //purpose  : 
1201 //=======================================================================
1202
1203 Standard_Real ChFi3d_Builder::Abscissa(const Standard_Integer IC,
1204                                        const TopoDS_Vertex& V) const
1205 {
1206   if(IC <= NbElements()){
1207     return Value(IC)->Absc(V);
1208   }
1209   return -1;
1210 }
1211
1212 //=======================================================================
1213 //function : RelativeAbscissa
1214 //purpose  : 
1215 //=======================================================================
1216
1217 Standard_Real ChFi3d_Builder::RelativeAbscissa(const Standard_Integer IC,
1218                                                const TopoDS_Vertex& V) const
1219 {
1220   if(IC <= NbElements()){
1221     return Abscissa(IC,V)/Length(IC);
1222   }
1223   return -1;
1224 }
1225
1226 //=======================================================================
1227 //function : Closed
1228 //purpose  : 
1229 //=======================================================================
1230
1231 Standard_Boolean ChFi3d_Builder::Closed(const Standard_Integer IC)const
1232 {
1233   if(IC <= NbElements()){
1234     return Value(IC)->IsClosed();
1235   }
1236   return Standard_False;
1237 }
1238
1239 //=======================================================================
1240 //function : ClosedAndTangent
1241 //purpose  : 
1242 //=======================================================================
1243
1244 Standard_Boolean ChFi3d_Builder::ClosedAndTangent
1245 (const Standard_Integer IC)const
1246 {
1247   if(IC <= NbElements()){
1248     return Value(IC)->IsPeriodic();
1249   }
1250   return Standard_False;
1251 }
1252