0024947: Redesign OCCT legacy type system -- automatic
[occt.git] / src / ShapeUpgrade / ShapeUpgrade_ConvertCurve3dToBezier.cxx
1 // Created on: 1999-05-13
2 // Created by: data exchange team
3 // Copyright (c) 1999-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 #include <ShapeUpgrade_ConvertCurve3dToBezier.ixx>
18 #include <Precision.hxx>
19 #include <Geom_TrimmedCurve.hxx>
20 #include <Geom_BezierCurve.hxx>
21 #include <ShapeExtend.hxx>
22 #include <Geom_Line.hxx>
23 #include <TColgp_Array1OfPnt.hxx>
24 #include <Geom_BSplineCurve.hxx>
25 #include <Geom_Conic.hxx>
26 #include <GeomConvert_ApproxCurve.hxx>
27 #include <GeomConvert.hxx>
28 #include <GeomConvert_BSplineCurveToBezierCurve.hxx>
29 #include <TColStd_Array1OfReal.hxx>
30 #include <TColGeom_HArray1OfCurve.hxx>
31 #include <Geom_Circle.hxx>
32 #include <Geom_Curve.hxx>
33
34 ShapeUpgrade_ConvertCurve3dToBezier::ShapeUpgrade_ConvertCurve3dToBezier()
35 {
36   mySegments = new TColGeom_HSequenceOfCurve;
37   mySplitParams = new TColStd_HSequenceOfReal;
38   myLineMode = Standard_True;
39   myCircleMode = Standard_True;
40   myConicMode = Standard_True;
41 }
42
43 //=======================================================================
44 //function : Compute
45 //purpose  : 
46 //=======================================================================
47
48 void ShapeUpgrade_ConvertCurve3dToBezier::Compute()
49 {
50   mySegments->Clear();
51   mySplitParams->Clear();
52   Standard_Real precision = Precision::PConfusion();
53   Standard_Real First =  mySplitValues->Value(1);
54   Standard_Real Last = mySplitValues->Value(mySplitValues->Length());
55   if(myCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
56     Handle(Geom_TrimmedCurve) tmp = Handle(Geom_TrimmedCurve)::DownCast (myCurve);
57     Handle(Geom_Curve) BasCurve = tmp->BasisCurve();
58     ShapeUpgrade_ConvertCurve3dToBezier converter;
59     converter.Init(BasCurve,First,Last);
60     converter.SetSplitValues(mySplitValues);
61     converter.Compute();
62     mySplitValues->ChangeSequence() = converter.SplitValues()->Sequence();
63     myNbCurves = mySplitValues->Length()-1;
64     myStatus |= converter.myStatus;
65     mySegments->ChangeSequence() = converter.Segments()->Sequence();
66     mySplitParams->ChangeSequence() = converter.SplitParams()->Sequence();
67     return;
68   }
69   else if(myCurve->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
70     Handle(Geom_BezierCurve) bezier = Handle(Geom_BezierCurve)::DownCast (myCurve);
71     myNbCurves = mySplitValues->Length()-1;
72     mySplitParams->Append(First);
73     mySplitParams->Append(Last);
74     if(First < precision && Last > 1 - precision) {
75       mySegments->Append(bezier);
76       myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
77     } else {
78       Handle(Geom_BezierCurve) besNew = Handle(Geom_BezierCurve)::DownCast(bezier->Copy());
79       besNew->Segment(First,Last);
80       mySegments->Append(besNew);
81       myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE2);
82     }
83     return;
84   }
85   else if(myCurve->IsKind(STANDARD_TYPE(Geom_Line))) {
86     Handle(Geom_Line) aLine = Handle(Geom_Line)::DownCast(myCurve);
87     myNbCurves = mySplitValues->Length()-1;
88     mySplitParams->Append(First);
89     mySplitParams->Append(Last);
90     if(!myLineMode) {
91       mySegments->Append(aLine);
92       myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
93       return;
94     }
95     TColgp_Array1OfPnt poles(1,2);
96     poles(1) = aLine->Value(First);
97     poles(2) = aLine->Value(Last);
98     Handle(Geom_BezierCurve) bezier = new Geom_BezierCurve(poles);
99     mySegments->Append(bezier);
100     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
101     return;
102   }
103   else if((myCurve->IsKind(STANDARD_TYPE(Geom_Conic))&&!myConicMode)||
104           (myCurve->IsKind(STANDARD_TYPE(Geom_Circle))&&!myCircleMode)) {
105     myNbCurves = mySplitValues->Length()-1;
106     mySplitParams->Append(First);
107     mySplitParams->Append(Last);
108     mySegments->Append(myCurve);
109     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
110     return;
111   }
112   else {
113     Handle(Geom_BSplineCurve) aBSpline;
114     Standard_Real Shift = 0.;
115     if(myCurve->IsKind(STANDARD_TYPE(Geom_Conic))) {
116       Handle(Geom_TrimmedCurve) tcurve = new Geom_TrimmedCurve(myCurve,First,Last); //protection agains parabols ets
117       GeomConvert_ApproxCurve approx (tcurve, Precision::Approximation(), 
118                                       GeomAbs_C1, 100, 6 );
119       if ( approx.HasResult() )
120         aBSpline = Handle(Geom_BSplineCurve)::DownCast(approx.Curve());
121       else {
122         Handle(Geom_TrimmedCurve) t3d = new Geom_TrimmedCurve(myCurve,First,Last);
123         aBSpline = GeomConvert::CurveToBSplineCurve(t3d,Convert_QuasiAngular);
124       }
125       Shift = First - aBSpline->FirstParameter();
126       First = aBSpline->FirstParameter();
127       Last = aBSpline->LastParameter();
128     }
129     else if(!myCurve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
130       aBSpline = GeomConvert::CurveToBSplineCurve(myCurve,Convert_QuasiAngular);
131     }
132     else
133       aBSpline = Handle(Geom_BSplineCurve)::DownCast(myCurve);
134     
135     Standard_Real bf = aBSpline->FirstParameter();
136     Standard_Real bl = aBSpline->LastParameter();
137     if(Abs(First-bf) < precision)
138       First = bf;
139     if(Abs(Last-bl) < precision)
140       Last = bl;
141     if(First < bf){
142 #ifdef OCCT_DEBUG
143       cout <<"Warning: The range of the edge exceeds the curve domain" <<endl;
144 #endif
145       First = bf;
146       mySplitValues->SetValue(1,First);
147     }
148     if(Last > bl){
149 #ifdef OCCT_DEBUG
150       cout <<"Warning: The range of the edge exceeds the curve domain" <<endl;
151 #endif
152       Last = bl;
153       mySplitValues->SetValue(mySplitValues->Length(),Last);
154     }
155     
156     GeomConvert_BSplineCurveToBezierCurve tool(aBSpline,First,Last,precision);
157     Standard_Integer nbArcs = tool.NbArcs();
158     TColStd_Array1OfReal knots(1,nbArcs+1);
159     tool.Knots(knots);
160     mySplitParams->Append(First+Shift);
161     Standard_Integer j; // svv Jan 10 2000 : porting on DEC
162     for(j = 1; j <=nbArcs; j++) {
163       Standard_Real nextKnot = knots(j+1)+Shift;
164       if(nextKnot - mySplitParams->Value(mySplitParams->Length()) > precision) {
165         mySegments->Append(tool.Arc(j));
166         mySplitParams->Append(knots(j+1)+Shift);
167       }
168     }
169     
170     First = mySplitValues->Value(1);
171     for(j = 2; j <= mySplitValues->Length(); j++) {
172       Last =  mySplitValues->Value(j);
173       for(Standard_Integer i = 2; i <= nbArcs+1; i++) {
174         Standard_Real valknot = knots(i)+Shift;
175         if(valknot <= First + precision) continue;
176         if(valknot >= Last - precision) break;
177         mySplitValues->InsertBefore(j++,valknot);
178       }
179       First = Last;
180     }
181     myNbCurves = mySplitValues->Length()-1;
182   }
183   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
184 }
185
186 //=======================================================================
187 //function : Build
188 //purpose  : 
189 //=======================================================================
190
191 void ShapeUpgrade_ConvertCurve3dToBezier::Build(const Standard_Boolean /*Segment*/)
192 {
193   Standard_Real prec = Precision::PConfusion();
194   Standard_Integer nb = mySplitValues->Length();
195   myResultingCurves =  new TColGeom_HArray1OfCurve (1,nb-1);
196   Standard_Real prevPar = 0.;
197   Standard_Integer j=2;
198   for(Standard_Integer i = 2; i <= nb; i++) {
199     Standard_Real par = mySplitValues->Value(i);
200     for(; j<= mySplitParams->Length(); j++) 
201       if(mySplitParams->Value(j)+prec > par) 
202         break;
203       else
204         prevPar = 0.;
205         
206     Handle(Geom_Curve) crv = Handle(Geom_Curve)::DownCast(mySegments->Value(j-1)->Copy());
207     if(crv->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
208       Handle(Geom_BezierCurve) bes = Handle(Geom_BezierCurve)::DownCast(crv);
209       Standard_Real uFact = mySplitParams->Value(j) - mySplitParams->Value(j-1);
210       Standard_Real pp = mySplitValues->Value(i-1);
211       Standard_Real length = (par - pp)/uFact;
212       bes->Segment(prevPar, prevPar+length);
213       prevPar += length;
214       myResultingCurves->SetValue(i-1,bes);
215     }
216     else 
217      myResultingCurves->SetValue(i-1,crv); 
218   }
219 }
220
221 //=======================================================================
222 //function : Segments
223 //purpose  : 
224 //=======================================================================
225
226 Handle(TColGeom_HSequenceOfCurve) ShapeUpgrade_ConvertCurve3dToBezier::Segments() const
227 {
228   return mySegments;
229 }
230
231 //=======================================================================
232 //function : SplitParams
233 //purpose  : 
234 //=======================================================================
235
236 Handle(TColStd_HSequenceOfReal) ShapeUpgrade_ConvertCurve3dToBezier::SplitParams() const
237 {
238   return mySplitParams;
239 }