0026173: Wrong result of ChFi3d_ChBuilder algorithm: incorrect processing of G1 junct...
[occt.git] / src / ChFiDS / ChFiDS_Spine.cxx
1 // Created on: 1993-11-18
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 // Modified by isg, Thu Mar 17 09:21:31 1994
18
19 #include <BRep_Tool.hxx>
20 #include <BRepAdaptor_Curve.hxx>
21 #include <ChFiDS_ErrorStatus.hxx>
22 #include <ChFiDS_HElSpine.hxx>
23 #include <ChFiDS_ListIteratorOfListOfHElSpine.hxx>
24 #include <ChFiDS_Spine.hxx>
25 #include <ElCLib.hxx>
26 #include <GCPnts_AbscissaPoint.hxx>
27 #include <gp_Circ.hxx>
28 #include <gp_Lin.hxx>
29 #include <gp_Pnt.hxx>
30 #include <gp_Vec.hxx>
31 #include <Precision.hxx>
32 #include <Standard_Type.hxx>
33 #include <TopExp.hxx>
34 #include <TopoDS_Edge.hxx>
35 #include <TopoDS_Vertex.hxx>
36
37 //=======================================================================
38 //function : ChFiDS_Spine
39 //purpose  : 
40 //=======================================================================
41 ChFiDS_Spine::ChFiDS_Spine():
42        splitdone(Standard_False),
43        tolesp(Precision::Confusion()),
44        firstprolon(Standard_False), 
45        lastprolon(Standard_False),
46        firstistgt(Standard_False), 
47        lastistgt(Standard_False),
48        hasfirsttgt(Standard_False), 
49        haslasttgt(Standard_False),
50        hasref(Standard_False)
51 {
52 }
53
54 ChFiDS_Spine::ChFiDS_Spine(const Standard_Real Tol):
55        splitdone(Standard_False),
56        tolesp(Tol),
57        firstprolon(Standard_False), 
58        lastprolon(Standard_False),
59        firstistgt(Standard_False), 
60        lastistgt(Standard_False),
61        hasfirsttgt(Standard_False), 
62        haslasttgt(Standard_False),
63        hasref(Standard_False)
64 {
65 }
66
67 //=======================================================================
68 //function : AppendElSpine
69 //purpose  : 
70 //=======================================================================
71
72 void ChFiDS_Spine::AppendElSpine(const Handle(ChFiDS_HElSpine)& Els)
73 {
74   elspines.Append(Els);
75 }
76
77 //=======================================================================
78 //function : ElSpine
79 //purpose  : 
80 //=======================================================================
81
82 Handle(ChFiDS_HElSpine) ChFiDS_Spine::ElSpine(const TopoDS_Edge& E) const 
83 {
84   return ElSpine(Index(E));
85 }
86
87 Handle(ChFiDS_HElSpine) ChFiDS_Spine::ElSpine(const Standard_Integer IE) const 
88 {
89   Standard_Real wmil = 0.5 * (FirstParameter(IE) + LastParameter(IE));
90   if(IsPeriodic()) wmil = ElCLib::InPeriod(wmil,FirstParameter(),LastParameter());
91   return ElSpine(wmil);
92 }
93
94 Handle(ChFiDS_HElSpine) ChFiDS_Spine::ElSpine(const Standard_Real W) const 
95 {
96   if (elspines.Extent() == 1)
97     return elspines.First();
98   else
99   {
100     ChFiDS_ListIteratorOfListOfHElSpine It(elspines);
101     for (; It.More(); It.Next()) {
102       Handle(ChFiDS_HElSpine) cur = It.Value();
103       Standard_Real uf = cur->FirstParameter();
104       Standard_Real ul = cur->LastParameter();
105       if(uf <= W && W <= ul) return cur;
106     }  
107     return Handle(ChFiDS_HElSpine)();
108   }
109 }
110
111 //=======================================================================
112 //function : ChangeElSpines
113 //purpose  : 
114 //=======================================================================
115
116 ChFiDS_ListOfHElSpine& ChFiDS_Spine::ChangeElSpines() 
117 {
118   return elspines;
119 }
120
121 //=======================================================================
122 //function : SplitDone
123 //purpose  : 
124 //=======================================================================
125
126 void ChFiDS_Spine::SplitDone(const Standard_Boolean B)
127 {
128   splitdone = B;
129 }
130
131 //=======================================================================
132 //function : SplitDone
133 //purpose  : 
134 //=======================================================================
135
136 Standard_Boolean ChFiDS_Spine::SplitDone() const 
137 {
138   return splitdone;
139 }
140
141 //=======================================================================
142 //function : Reset
143 //purpose  : 
144 //=======================================================================
145
146 void ChFiDS_Spine::Reset(const Standard_Boolean AllData)
147 {
148   splitdone = Standard_False;
149   //if(AllData && !isconstant.IsNull()) isconstant->ChangeArray1().Init(0);
150   elspines.Clear();
151   if(AllData){
152     firstparam = 0.;
153     lastparam = abscissa->Value(abscissa->Upper());
154     firstprolon = lastprolon = Standard_False;
155   }
156 }
157
158 //=======================================================================
159 //function : FirstParameter
160 //purpose  : 
161 //=======================================================================
162
163 Standard_Real  ChFiDS_Spine::FirstParameter() const
164 {
165   if(firstprolon) return firstparam;
166   return 0.;
167 }
168
169
170 //=======================================================================
171 //function : LastParameter
172 //purpose  : 
173 //=======================================================================
174
175 Standard_Real  ChFiDS_Spine::LastParameter() const
176 {
177   if(lastprolon) return lastparam;
178   return abscissa->Value(abscissa->Upper());
179 }
180
181 //=======================================================================
182 //function : SetFirstParameter
183 //purpose  : 
184 //=======================================================================
185
186 void ChFiDS_Spine::SetFirstParameter(const Standard_Real Par) 
187 {
188 #ifdef OCCT_DEBUG
189   if(Par >= Precision::Confusion()) 
190     cout<<"Interior extension at the start of guideline"<<endl;
191   if(IsPeriodic())
192     cout<<"WARNING!!! Extension on periodic guideline."<<endl;
193 #endif
194   firstprolon = Standard_True;
195   firstparam = Par;
196 }
197
198
199 //=======================================================================
200 //function : SetLastParameter
201 //purpose  : 
202 //=======================================================================
203
204 void ChFiDS_Spine::SetLastParameter(const Standard_Real Par) 
205 {
206 #ifdef OCCT_DEBUG
207   Standard_Real lll = abscissa->Value(abscissa->Upper());
208   if((Par - lll) <= -Precision::Confusion()) 
209     cout<<"Interior extension at the end of guideline"<<endl;
210   if(IsPeriodic())
211     cout<<"WARNING!!! Extension on periodic guideline."<<endl;
212 #endif
213   lastprolon = Standard_True;
214   lastparam = Par;
215 }
216
217 //=======================================================================
218 //function : FirstParameter
219 //purpose  : 
220 //=======================================================================
221
222 Standard_Real  ChFiDS_Spine::FirstParameter
223 (const Standard_Integer IndexSpine) const 
224 {
225   if (IndexSpine==1) return 0.;
226   return abscissa->Value(IndexSpine-1);
227 }
228
229 //=======================================================================
230 //function : LastParameter
231 //purpose  : 
232 //=======================================================================
233
234 Standard_Real  ChFiDS_Spine::LastParameter
235 (const Standard_Integer IndexSpine) const 
236 {
237   return abscissa->Value(IndexSpine);
238 }
239
240 //=======================================================================
241 //function : Length
242 //purpose  : 
243 //=======================================================================
244
245 Standard_Real  ChFiDS_Spine::Length
246 (const Standard_Integer IndexSpine) const 
247 {
248   if (IndexSpine==1) return abscissa->Value(IndexSpine);
249   return abscissa->Value(IndexSpine) - abscissa->Value(IndexSpine-1);
250 }
251
252 //=======================================================================
253 //function : IsPeriodic
254 //purpose  : 
255 //=======================================================================
256
257 Standard_Boolean ChFiDS_Spine::IsPeriodic() const
258 {
259   return (firstState == ChFiDS_Closed);
260 }
261
262
263 //=======================================================================
264 //function : IsClosed
265 //purpose  : 
266 //=======================================================================
267
268 Standard_Boolean ChFiDS_Spine::IsClosed() const
269 {
270   return (FirstVertex().IsSame(LastVertex()));
271 }
272
273
274 //=======================================================================
275 //function : FirstVertex
276 //purpose  : 
277 //=======================================================================
278
279 TopoDS_Vertex ChFiDS_Spine::FirstVertex() const
280 {
281   TopoDS_Edge E = TopoDS::Edge(spine.First());
282   if(E.Orientation() == TopAbs_FORWARD) return TopExp::FirstVertex(E); 
283   return TopExp::LastVertex(E); 
284 }
285
286
287 //=======================================================================
288 //function : LastVertex
289 //purpose  : 
290 //=======================================================================
291
292 TopoDS_Vertex ChFiDS_Spine::LastVertex() const
293 {
294   TopoDS_Edge E = TopoDS::Edge(spine.Last());
295   if(E.Orientation() == TopAbs_FORWARD) return TopExp::LastVertex(E); 
296   return TopExp::FirstVertex(E); 
297 }
298
299
300 //=======================================================================
301 //function : Absc
302 //purpose  : 
303 //=======================================================================
304
305 Standard_Real ChFiDS_Spine::Absc(const TopoDS_Vertex& V) const
306 {
307   TopoDS_Vertex d,f;
308   TopoDS_Edge E;
309   for(Standard_Integer i = 1; i<=spine.Length(); i++){
310     E = TopoDS::Edge(spine.Value(i));
311     TopExp::Vertices(E,d,f);
312     if(d.IsSame(V) && E.Orientation() == TopAbs_FORWARD){
313       return FirstParameter(i);
314     }
315     if(d.IsSame(V) && E.Orientation() == TopAbs_REVERSED){
316       return LastParameter(i);
317     }
318     if(f.IsSame(V) && E.Orientation() == TopAbs_FORWARD){
319       return LastParameter(i);
320     }
321     if(f.IsSame(V) && E.Orientation() == TopAbs_REVERSED){
322       return FirstParameter(i);
323     }
324   }
325   return -1.;
326 }
327
328
329 //=======================================================================
330 //function : Period
331 //purpose  : 
332 //=======================================================================
333
334 Standard_Real ChFiDS_Spine::Period() const
335 {
336   if(!IsPeriodic()) Standard_Failure::Raise("Non-periodic Spine");
337   return abscissa->Value(abscissa->Upper());
338 }
339
340
341 //=======================================================================
342 //function : Resolution
343 //purpose  : 
344 //=======================================================================
345
346 Standard_Real ChFiDS_Spine::Resolution(const Standard_Real R3d) const
347 {
348   return R3d;
349 }
350
351
352 //=======================================================================
353 //function : SetFirstTgt
354 //purpose  : 
355 //=======================================================================
356
357 void  ChFiDS_Spine::SetFirstTgt(const Standard_Real W)
358 {
359   if(IsPeriodic()) Standard_Failure::Raise
360     ("No extension by tangent on periodic contours"); 
361 #ifdef OCCT_DEBUG
362   if(W >= Precision::Confusion()) 
363     cout<<"Interior extension at start of the guideline"<<endl;
364 #endif
365   //The flag is suspended if is already positioned to avoid  
366   //stopping d1
367   hasfirsttgt = Standard_False;
368   D1(W,firstori,firsttgt);
369   //and it is reset.
370   hasfirsttgt = Standard_True;
371   firsttgtpar = W;
372 }
373
374
375 //=======================================================================
376 //function : SetLastTgt
377 //purpose  : 
378 //=======================================================================
379
380 void  ChFiDS_Spine::SetLastTgt(const Standard_Real W)
381 {
382   if(IsPeriodic()) Standard_Failure::Raise
383     ("No extension by tangent periodic contours"); 
384
385 #ifdef OCCT_DEBUG
386   Standard_Real L = W - abscissa->Value(abscissa->Upper());
387   if(L <= -Precision::Confusion()) 
388     cout<<"Interior extension at the end of guideline"<<endl;
389 #endif
390   //The flag is suspended if is already positioned to avoid  
391   //stopping d1 
392   haslasttgt = Standard_False;
393   D1(W,lastori,lasttgt);
394   //and it is reset.
395   haslasttgt = Standard_True;
396   lasttgtpar = W;
397 }
398
399
400 //=======================================================================
401 //function : HasFirstTgt
402 //purpose  : 
403 //=======================================================================
404
405 Standard_Boolean  ChFiDS_Spine::HasFirstTgt()const
406 {
407   return hasfirsttgt;
408 }
409
410 //=======================================================================
411 //function : HasLastTgt
412 //purpose  : 
413 //=======================================================================
414
415 Standard_Boolean  ChFiDS_Spine::HasLastTgt()const
416 {
417   return haslasttgt;
418 }
419
420 //=======================================================================
421 //function : SetReference
422 //purpose  : 
423 //=======================================================================
424
425 void  ChFiDS_Spine::SetReference(const Standard_Real W)
426 {
427   hasref = Standard_True;
428   Standard_Real lll = abscissa->Value(abscissa->Upper());
429   if(IsPeriodic()) valref = ElCLib::InPeriod(W,0.,lll);
430   else valref = W;
431 }
432
433
434 //=======================================================================
435 //function : SetReference
436 //purpose  : 
437 //=======================================================================
438
439 void  ChFiDS_Spine::SetReference(const Standard_Integer I)
440 {
441   hasref = Standard_True;
442   if(I == 1) valref = abscissa->Value(1)*0.5;
443   else valref = (abscissa->Value(I) + abscissa->Value(I-1))*0.5;
444 }
445
446
447 //=======================================================================
448 //function : Index
449 //purpose  : 
450 //=======================================================================
451
452 Standard_Integer ChFiDS_Spine::Index(const Standard_Real W,
453                                      const Standard_Boolean Forward) const
454 {
455   Standard_Integer ind, len = abscissa->Length();
456   Standard_Real par = W,last = abscissa->Value(abscissa->Upper());
457   Standard_Real f = 0., l = 0., t = Max(tolesp,Precision::Confusion());
458
459   if(IsPeriodic() && Abs(par) >= t && Abs(par-last) >= t) 
460     par = ElCLib::InPeriod(par,0.,last);
461   
462   for (ind=1; ind <= len; ind++) {
463     f = l;
464     l = abscissa->Value(ind);
465     if (par<l || ind==len) break;
466   }
467   if (Forward && ind<len && Abs(par-l) < t) ind++;
468   else if (!Forward && ind > 1 && Abs(par-f) < t) ind--;
469   else if (Forward && IsPeriodic() && ind == len && Abs(par-l) < t) ind = 1;
470   else if (!Forward && IsPeriodic() && ind == 1 && Abs(par-f) < t) ind = len;
471   return ind;
472 }
473
474 //=======================================================================
475 //function : Index
476 //purpose  : 
477 //=======================================================================
478
479 Standard_Integer ChFiDS_Spine::Index (const TopoDS_Edge& E) const
480 {
481   for(Standard_Integer IE = 1; IE <= spine.Length(); IE++){
482     if(E.IsSame(spine.Value(IE))) return IE;
483   }
484   return 0;
485 }
486
487 //=======================================================================
488 //function : UnsetReference
489 //purpose  : 
490 //=======================================================================
491
492 void  ChFiDS_Spine::UnsetReference()
493 {
494   hasref = Standard_False;
495 }
496
497 //=======================================================================
498 //function : Load
499 //purpose  : 
500 //=======================================================================
501
502 void  ChFiDS_Spine::Load()
503 {
504   if(!abscissa.IsNull()){
505 #ifdef OCCT_DEBUG
506     cout<<"new load of CE"<<endl;
507 #endif
508   }
509   Standard_Integer len = spine.Length();
510   abscissa = new TColStd_HArray1OfReal(1,len);
511   Standard_Real a1 = 0.;
512   for (Standard_Integer i = 1; i <= len; i++){
513     myCurve.Initialize(TopoDS::Edge(spine.Value(i)));
514     a1 += GCPnts_AbscissaPoint::Length(myCurve);
515     abscissa->SetValue(i,a1);
516   }
517   indexofcurve =1;
518   myCurve.Initialize(TopoDS::Edge(spine.Value(1)));
519 }
520
521
522 //=======================================================================
523 //function : Absc
524 //purpose  : 
525 //=======================================================================
526
527 Standard_Real ChFiDS_Spine::Absc(const Standard_Real U) 
528 {
529   return Absc(U,indexofcurve);
530 }
531
532 //=======================================================================
533 //function : Absc
534 //purpose  : 
535 //=======================================================================
536
537 Standard_Real ChFiDS_Spine::Absc(const Standard_Real U,
538                                  const Standard_Integer I) 
539 {
540
541   
542   if(indexofcurve != I){
543     void* p = (void*)this;
544     ((ChFiDS_Spine*)p)->indexofcurve = I;
545     ((ChFiDS_Spine*)p)->myCurve.Initialize(TopoDS::Edge(spine.Value(I)));
546   }
547   Standard_Real L = FirstParameter(I);
548   if (spine.Value(I).Orientation() == TopAbs_REVERSED) {
549     L += GCPnts_AbscissaPoint::Length(myCurve,U,myCurve.LastParameter());
550   }
551   else{
552     L += GCPnts_AbscissaPoint::Length(myCurve,myCurve.FirstParameter(),U);
553   }
554   return L;
555 }
556
557 //=======================================================================
558 //function : Parameter
559 //purpose  : 
560 //=======================================================================
561
562 void ChFiDS_Spine::Parameter(const Standard_Real AbsC,
563                              Standard_Real& U,
564                              const Standard_Boolean Oriented) 
565 {
566   Standard_Integer Index;
567   for (Index=1;Index<abscissa->Length();Index++) {
568     if (AbsC<abscissa->Value(Index)) break;
569   }
570   Parameter(Index,AbsC,U,Oriented);
571 }
572
573
574 //=======================================================================
575 //function : Parameter
576 //purpose  : 
577 //=======================================================================
578
579 void ChFiDS_Spine::Parameter(const Standard_Integer Index,
580                              const Standard_Real AbsC,
581                              Standard_Real& U,
582                              const Standard_Boolean Oriented) 
583 {
584
585   if (Index != indexofcurve) {
586     void* p = (void*)this;
587     ((ChFiDS_Spine*)p)->indexofcurve = Index;
588     ((ChFiDS_Spine*)p)->myCurve.Initialize(TopoDS::Edge(spine.Value(Index)));
589   }
590   Standard_Real L;
591   TopAbs_Orientation Or = spine.Value(Index).Orientation();
592   if (Or == TopAbs_REVERSED) {
593     L = abscissa->Value(indexofcurve)-AbsC; 
594   }
595   else if (indexofcurve==1) {
596     L = AbsC;
597   }  
598   else {
599     L = AbsC - abscissa->Value(indexofcurve-1); 
600   }
601   Standard_Real t = L/Length(Index);
602   Standard_Real uapp = (1. - t) * myCurve.FirstParameter() + t * myCurve.LastParameter();
603 //  GCPnts_AbscissaPoint GCP;
604 //  GCP.Perform(myCurve,L,myCurve.FirstParameter(),uapp,BRep_Tool::Tolerance(myCurve.Edge()));
605   GCPnts_AbscissaPoint GCP(myCurve,L,myCurve.FirstParameter(),uapp);
606   U = GCP.Parameter();
607   if (Or == TopAbs_REVERSED && Oriented) {
608     U = (myCurve.LastParameter()+myCurve.FirstParameter()) - U;
609   }
610 }
611
612
613 //=======================================================================
614 //function : Prepare
615 //purpose  : 
616 //=======================================================================
617
618 void  ChFiDS_Spine::Prepare(Standard_Real& L, 
619                             Standard_Integer& Ind) const
620 {
621   Standard_Real tol = Max(tolesp,Precision::Confusion());
622   Standard_Real last = abscissa->Value(abscissa->Upper());
623   Standard_Integer len = abscissa->Length();
624   if(IsPeriodic() && Abs(L) >= tol && Abs(L-last) >= tol) 
625     L = ElCLib::InPeriod(L,0.,last);
626
627   if(hasfirsttgt && (L <= firsttgtpar)){
628     if(hasref && valref >= L && Abs(L-firsttgtpar) <= tol){
629       Ind = Index(L);
630     }
631     else{Ind = -1; L -= firsttgtpar;} 
632   }
633   else if(L <= 0.){Ind = 1;}
634   else if(haslasttgt && (L >= lasttgtpar)){
635     if(hasref && valref <= L && Abs(L-lasttgtpar) <= tol){
636       Ind = Index(L); 
637     }
638     else{Ind = len + 1; L -= lasttgtpar;} 
639   }
640   else if(L >= last){Ind = len;}
641   else{
642     for (Ind=1;Ind < len;Ind++) {
643       if (L<abscissa->Value(Ind)) break;
644     }
645     if(hasref){
646       if (L >= valref && Ind != 1){
647         if(Abs(L-abscissa->Value(Ind-1)) <= Precision::Confusion()) Ind--;
648       }
649       else if (L <= valref && Ind != len){
650         if(Abs(L-abscissa->Value(Ind)) <= Precision::Confusion()) Ind++;
651       }
652     }
653   }
654   if(Ind >= 1 && Ind <= len){ 
655     if (spine.Value(Ind).Orientation() == TopAbs_REVERSED){
656       L = abscissa->Value(Ind) - L; 
657     }
658     else if (Ind!=1){
659       L -= abscissa->Value(Ind - 1); 
660     }
661   }
662 }
663
664 //=======================================================================
665 //function : Value
666 //purpose  : 
667 //=======================================================================
668
669 gp_Pnt  ChFiDS_Spine::Value(const Standard_Real AbsC) 
670 {
671
672   Standard_Integer Index;
673   Standard_Real L = AbsC;
674
675   Prepare(L,Index);
676
677   if (Index == -1) {
678     gp_Pnt Pp = firstori;
679     gp_Vec Vp = firsttgt;
680     Vp.Multiply(L);
681     Pp.Translate(Vp);
682     return Pp;
683   }
684   else if (Index == (abscissa->Length() + 1)) {
685     gp_Pnt Pp = lastori;
686     gp_Vec Vp = lasttgt;
687     Vp.Multiply(L);
688     Pp.Translate(Vp);
689     return Pp;
690   }
691   if (Index != indexofcurve) {
692     void* p = (void*)this;
693     ((ChFiDS_Spine*)p)->indexofcurve = Index;
694     ((ChFiDS_Spine*)p)->myCurve.Initialize(TopoDS::Edge(spine.Value(Index)));
695   }
696   Standard_Real t = L/Length(Index);
697   Standard_Real uapp = (1. - t) * myCurve.FirstParameter() + t * myCurve.LastParameter();
698 //  GCPnts_AbscissaPoint GCP;
699 //  GCP.Perform(myCurve,L,myCurve.FirstParameter(),uapp,BRep_Tool::Tolerance(myCurve.Edge()));
700   GCPnts_AbscissaPoint GCP(myCurve,L,myCurve.FirstParameter(),uapp);
701   return myCurve.Value(GCP.Parameter());
702 }
703
704 //=======================================================================
705 //function : D0
706 //purpose  : 
707 //=======================================================================
708
709 void  ChFiDS_Spine::D0(const Standard_Real AbsC, gp_Pnt& P) 
710 {
711   P = Value(AbsC);
712 }
713
714 //=======================================================================
715 //function : D1
716 //purpose  : 
717 //=======================================================================
718
719 void  ChFiDS_Spine::D1(const Standard_Real AbsC, 
720                                    gp_Pnt& P, 
721                                    gp_Vec& V1) 
722 {
723   Standard_Integer Index;
724   Standard_Real L = AbsC;
725
726   Prepare(L,Index);
727
728   if (Index == -1) {
729     P = firstori;
730     V1 = firsttgt;
731     gp_Vec Vp = firsttgt;
732     Vp.Multiply(L);
733     P.Translate(Vp);
734   }
735   else if (Index == (abscissa->Length() + 1)) {
736     P = lastori;
737     V1 = lasttgt;
738     gp_Vec Vp = lasttgt;
739     Vp.Multiply(L);
740     P.Translate(Vp);
741   }
742   else {
743     if (Index != indexofcurve) {
744       void* p = (void*)this;
745       ((ChFiDS_Spine*)p)->indexofcurve = Index;
746       ((ChFiDS_Spine*)p)->myCurve.Initialize(TopoDS::Edge(spine.Value(Index)));
747     }
748     Standard_Real t = L/Length(Index);
749     Standard_Real uapp = (1. - t) * myCurve.FirstParameter() + t * myCurve.LastParameter();
750 //    GCPnts_AbscissaPoint GCP;
751 //    GCP.Perform(myCurve,L,myCurve.FirstParameter(),uapp,BRep_Tool::Tolerance(myCurve.Edge()));
752     GCPnts_AbscissaPoint GCP(myCurve,L,myCurve.FirstParameter(),uapp);
753     myCurve.D1(GCP.Parameter(),P,V1);
754     Standard_Real D1 = 1./V1.Magnitude();
755     if (spine.Value(Index).Orientation() == TopAbs_REVERSED) D1 = -D1;
756     V1.Multiply(D1);
757   }
758 }
759
760
761 //=======================================================================
762 //function : D2
763 //purpose  : 
764 //=======================================================================
765
766 void  ChFiDS_Spine::D2(const Standard_Real AbsC, 
767                                    gp_Pnt& P, 
768                                    gp_Vec& V1, 
769                                    gp_Vec& V2) 
770 {
771
772   Standard_Integer Index;
773   Standard_Real L = AbsC;
774
775   Prepare(L,Index);
776
777   if (Index == -1) {
778     P = firstori;
779     V1 = firsttgt;
780     V2.SetCoord(0.,0.,0.);
781     gp_Vec Vp = firsttgt;
782     Vp.Multiply(L);
783     P.Translate(Vp);
784   }
785   else if (Index == (abscissa->Length() + 1)) {
786     P = lastori;
787     V1 = lasttgt;
788     V2.SetCoord(0.,0.,0.);
789     gp_Vec Vp = lasttgt;
790     Vp.Multiply(L);
791     P.Translate(Vp);
792   }
793   else {
794     if (Index != indexofcurve) {
795       void* p = (void*)this;
796       ((ChFiDS_Spine*)p)->indexofcurve = Index;
797       ((ChFiDS_Spine*)p)->myCurve.Initialize(TopoDS::Edge(spine.Value(Index)));
798     }
799     Standard_Real t = L/Length(Index);
800     Standard_Real uapp = (1. - t) * myCurve.FirstParameter() + t * myCurve.LastParameter();
801 //    GCPnts_AbscissaPoint GCP;
802 //    GCP.Perform(myCurve,L,myCurve.FirstParameter(),uapp,BRep_Tool::Tolerance(myCurve.Edge()));
803     GCPnts_AbscissaPoint GCP(myCurve,L,myCurve.FirstParameter(),uapp);
804     myCurve.D2(GCP.Parameter(),P,V1,V2);
805     Standard_Real N1 = V1.SquareMagnitude();
806     Standard_Real D2 = -(V1.Dot(V2))*(1./N1)*(1./N1);
807     V2.Multiply(1./N1);
808     N1 = Sqrt(N1);
809     gp_Vec Va = V1.Multiplied(D2);
810     V2.Add(Va);
811     Standard_Real D1 = 1./N1;
812     if (spine.Value(Index).Orientation() == TopAbs_REVERSED) D1 = -D1;
813     V1.Multiply(D1);
814   }
815 }
816
817 //=======================================================================
818 //function : SetCurrent
819 //purpose  : 
820 //=======================================================================
821
822 void ChFiDS_Spine::SetCurrent(const Standard_Integer Index)
823 {  
824   if (Index != indexofcurve)  {
825     indexofcurve = Index;
826     myCurve.Initialize(TopoDS::Edge(spine.Value(indexofcurve)));
827   }
828
829
830 //=======================================================================
831 //function : CurrentElementarySpine
832 //purpose  : 
833 //=======================================================================
834
835 const BRepAdaptor_Curve&  ChFiDS_Spine::CurrentElementarySpine
836 (const Standard_Integer Index) 
837 {
838   if (Index != indexofcurve)  {
839     indexofcurve = Index;
840     myCurve.Initialize(TopoDS::Edge(spine.Value(indexofcurve)));
841   }
842   return myCurve;
843 }
844
845 //=======================================================================
846 //function : GetType
847 //purpose  : 
848 //=======================================================================
849
850 GeomAbs_CurveType ChFiDS_Spine::GetType() const
851 {
852   return myCurve.GetType();
853 }
854
855 //=======================================================================
856 //function : Line
857 //purpose  : 
858 //=======================================================================
859
860 gp_Lin ChFiDS_Spine::Line() const
861 {
862   gp_Lin LL(myCurve.Line());
863   if (spine.Value(indexofcurve).Orientation() == TopAbs_REVERSED) {
864     LL.Reverse();
865     LL.SetLocation(myCurve.Value(myCurve.LastParameter()));
866   }
867   else {
868     LL.SetLocation(myCurve.Value(myCurve.FirstParameter()));
869   }
870   return LL;
871 }
872
873
874 //=======================================================================
875 //function : Circle
876 //purpose  : 
877 //=======================================================================
878
879 gp_Circ ChFiDS_Spine::Circle() const
880 {
881   gp_Ax2 Ac = myCurve.Circle().Position();
882   gp_Dir Dc(gp_Vec(Ac.Location(),myCurve.Value(myCurve.FirstParameter())));
883   gp_Dir ZZ(Ac.Direction());
884   
885   if (spine.Value(indexofcurve).Orientation() == TopAbs_REVERSED) {
886     Dc = gp_Dir(gp_Vec(Ac.Location(),myCurve.Value(myCurve.LastParameter())));
887     ZZ.Reverse();
888   }
889   gp_Ax2 A(Ac.Location(),ZZ,Dc);
890   return gp_Circ(A,myCurve.Circle().Radius());
891 }
892 //=======================================================================
893 //function : SetErrorStatus
894 //purpose  : met a jour le statut d'erreur 
895 //=======================================================================
896 void  ChFiDS_Spine::SetErrorStatus(const ChFiDS_ErrorStatus state)
897 {
898   errorstate=state;
899 }
900 //=======================================================================
901 //function : ErrorStatus
902 //purpose  : renvoie le statut d'erreur concernant la spine 
903 //=======================================================================
904
905 ChFiDS_ErrorStatus  ChFiDS_Spine::ErrorStatus()const 
906 {
907   return errorstate;
908 }