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