0026466: UnifySameDomain creates invalid result shape from valid input shape
[occt.git] / src / ShapeUpgrade / ShapeUpgrade_ConvertCurve2dToBezier.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 <Geom2d_BezierCurve.hxx>
19 #include <Geom2d_BSplineCurve.hxx>
20 #include <Geom2d_Conic.hxx>
21 #include <Geom2d_Line.hxx>
22 #include <Geom2d_TrimmedCurve.hxx>
23 #include <Geom2dConvert.hxx>
24 #include <Geom2dConvert_ApproxCurve.hxx>
25 #include <Geom2dConvert_BSplineCurveToBezierCurve.hxx>
26 #include <Geom_Curve.hxx>
27 #include <GeomTools.hxx>
28 #include <Precision.hxx>
29 #include <ShapeCustom_Curve2d.hxx>
30 #include <ShapeExtend.hxx>
31 #include <ShapeUpgrade_ConvertCurve2dToBezier.hxx>
32 #include <Standard_Type.hxx>
33 #include <TColGeom2d_HArray1OfCurve.hxx>
34 #include <TColgp_Array1OfPnt2d.hxx>
35 #include <TColStd_Array1OfReal.hxx>
36
37 ShapeUpgrade_ConvertCurve2dToBezier::ShapeUpgrade_ConvertCurve2dToBezier()
38 {
39   mySegments = new TColGeom2d_HSequenceOfCurve;
40   mySplitParams = new TColStd_HSequenceOfReal;
41 }
42
43 static Handle(Geom2d_BezierCurve) MakeBezier2d(const Handle(Geom2d_Curve)& theCurve2d,
44                                                const Standard_Real theFirst,
45                                                const Standard_Real theLast)
46 {
47   TColgp_Array1OfPnt2d poles(1,2);
48   poles(1) = theCurve2d->Value(theFirst);
49   poles(2) = theCurve2d->Value(theLast);
50   Handle(Geom2d_BezierCurve) bezier = new Geom2d_BezierCurve(poles);
51   return bezier;
52 }
53
54
55 //=======================================================================
56 //function : Compute
57 //purpose  : 
58 //=======================================================================
59
60 void ShapeUpgrade_ConvertCurve2dToBezier::Compute()
61 {
62   mySegments->Clear();
63   mySplitParams->Clear();
64   Standard_Real precision = Precision::PConfusion();
65   Standard_Real First =  mySplitValues->Value(1);
66   Standard_Real Last = mySplitValues->Value(mySplitValues->Length());
67   
68   // PTV Try to create line2d from myCurve
69   if ( myCurve->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) ||
70        myCurve->IsKind(STANDARD_TYPE(Geom2d_BezierCurve)) )
71   {
72     // static function`s code getted from ShapeConvert
73     Standard_Real tmpF, tmpL, aDeviation;
74     Handle(Geom2d_Line) aTmpLine2d = 
75       ShapeCustom_Curve2d::ConvertToLine2d(myCurve, First, Last, Precision::Approximation(),
76                                                tmpF, tmpL, aDeviation);
77     if (!aTmpLine2d.IsNull() && (aDeviation <= Precision::Approximation()) )
78     {
79       Handle(Geom2d_BezierCurve) bezier = MakeBezier2d(aTmpLine2d, tmpF, tmpL);
80       mySegments->Append(bezier);
81       mySplitParams->Append(First);
82       mySplitParams->Append(Last);
83       myNbCurves = mySplitValues->Length()-1;
84       myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
85       return;
86     }
87   }
88   
89   if(myCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) {
90     Handle(Geom2d_TrimmedCurve) tmp = Handle(Geom2d_TrimmedCurve)::DownCast (myCurve);
91     Handle(Geom2d_Curve) BasCurve = tmp->BasisCurve();
92     ShapeUpgrade_ConvertCurve2dToBezier converter;
93     //converter.Init(BasCurve,Max(First,BasCurve->FirstParameter()),Min(Last,BasCurve->LastParameter())); //???
94     converter.Init(BasCurve,First,Last);
95     converter.SetSplitValues(mySplitValues);
96     converter.Compute();
97     mySplitValues->Clear();
98     mySplitValues->ChangeSequence() = converter.SplitValues()->Sequence();
99     myNbCurves = mySplitValues->Length()-1;
100     myStatus |= converter.myStatus;
101     mySegments->ChangeSequence() = converter.Segments()->Sequence();
102     mySplitParams->ChangeSequence() = converter.SplitParams()->Sequence();
103     return;
104   }
105   else if(myCurve->IsKind(STANDARD_TYPE(Geom2d_BezierCurve))) {
106     Handle(Geom2d_BezierCurve) bezier = Handle(Geom2d_BezierCurve)::DownCast (myCurve);
107     myNbCurves = mySplitValues->Length()-1;
108     mySplitParams->Append(First);
109     mySplitParams->Append(Last);
110     if(First < precision && Last > 1 - precision) {
111       mySegments->Append(bezier);
112       myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
113     } else {
114       Handle(Geom2d_BezierCurve) besNew = Handle(Geom2d_BezierCurve)::DownCast(bezier->Copy());
115       besNew->Segment(First,Last);
116       mySegments->Append(besNew);
117       myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE2);
118     }
119     return;
120   }
121   else if(myCurve->IsKind(STANDARD_TYPE(Geom2d_Line))) {
122     Handle(Geom2d_Line) aLine2d = Handle(Geom2d_Line)::DownCast(myCurve);
123     Handle(Geom2d_BezierCurve) bezier = MakeBezier2d(aLine2d, First, Last);    
124     mySegments->Append(bezier);
125     mySplitParams->Append(First);
126     mySplitParams->Append(Last);
127     myNbCurves = mySplitValues->Length()-1;
128     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
129     return;
130   }
131   else {
132     Handle(Geom2d_BSplineCurve) aBSpline2d;
133     Standard_Real Shift = 0.;
134     if(myCurve->IsKind(STANDARD_TYPE(Geom2d_Conic))) {
135       Handle(Geom2d_Curve) tcurve = new Geom2d_TrimmedCurve(myCurve,First,Last); //protection agains parabols ets
136       Geom2dConvert_ApproxCurve approx (tcurve, Precision::Approximation(), 
137                                         GeomAbs_C1, 100, 6 );
138       if ( approx.HasResult() )
139         aBSpline2d = Handle(Geom2d_BSplineCurve)::DownCast(approx.Curve());
140       else 
141         aBSpline2d = Geom2dConvert::CurveToBSplineCurve(tcurve,Convert_QuasiAngular);
142       
143       Shift = First - aBSpline2d->FirstParameter();
144       First = aBSpline2d->FirstParameter();
145       Last = aBSpline2d->LastParameter();
146     }
147     else if(!myCurve->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) {
148       aBSpline2d = Geom2dConvert::CurveToBSplineCurve(myCurve,Convert_QuasiAngular);
149     }
150     else
151       aBSpline2d = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
152     
153     Standard_Real bf = aBSpline2d->FirstParameter();
154     Standard_Real bl = aBSpline2d->LastParameter(); 
155     if(Abs(First-bf) < precision)
156       First = bf;
157     if(Abs(Last-bl) < precision)
158       Last = bl;
159     if(First < bf){
160 #ifdef OCCT_DEBUG
161       cout <<"Warning: The range of the edge exceeds the pcurve domain" <<endl;
162 #endif
163       First = bf;
164       mySplitValues->SetValue(1,First);
165     }
166     if(Last > bl){
167 #ifdef OCCT_DEBUG
168       cout <<"Warning: The range of the edge exceeds the pcurve domain" <<endl;
169 #endif
170       Last = bl;
171       mySplitValues->SetValue(mySplitValues->Length(),Last);
172     }
173
174     // PTV 20.12.2001 Try to simpify BSpline Curve
175     ShapeCustom_Curve2d::SimplifyBSpline2d (aBSpline2d, Precision::Approximation());
176     
177     Geom2dConvert_BSplineCurveToBezierCurve tool(aBSpline2d,First,Last,precision);
178     Standard_Integer nbArcs = tool.NbArcs();
179     TColStd_Array1OfReal knots(1,nbArcs+1);
180     tool.Knots(knots);
181     mySplitParams->Append(First+Shift);
182     Standard_Integer j; // svv Jan 10 2000 : porting on DEC
183     
184     Standard_Real newFirst = First+Shift;
185     Standard_Real newLast = First+Shift;
186     
187     for(j = 1; j <=nbArcs; j++) {
188       Standard_Real nextKnot = knots(j+1)+Shift;
189       if(nextKnot - mySplitParams->Value(mySplitParams->Length()) > precision) {
190         Handle(Geom2d_Curve) aCrv2d = tool.Arc(j);
191         if ( aCrv2d->IsKind(STANDARD_TYPE(Geom2d_BezierCurve)) )
192         {
193           newFirst = newLast;
194           newLast = nextKnot;
195           Standard_Real tmpF, tmpL, aDeviation;
196           Handle(Geom2d_Line) aTmpLine2d = 
197             ShapeCustom_Curve2d::ConvertToLine2d(aCrv2d, newFirst, newLast, Precision::Approximation(),
198                                                      tmpF, tmpL, aDeviation);
199           if (!aTmpLine2d.IsNull() && (aDeviation <= Precision::Approximation()) )
200           {
201             Handle(Geom2d_BezierCurve) bezier = MakeBezier2d(aBSpline2d, newFirst, newLast);
202             mySegments->Append(bezier);
203             mySplitParams->Append(newLast);
204             continue;
205           }
206         }
207         mySegments->Append(aCrv2d);
208         mySplitParams->Append(nextKnot);
209       }
210     }
211     
212     First = mySplitValues->Value(1);
213     for(j = 2; j <= mySplitValues->Length(); j++) {
214       Last =  mySplitValues->Value(j);
215       for(Standard_Integer i = 2; i <= nbArcs+1; i++) {
216         Standard_Real valknot = knots(i)+Shift;
217         if(valknot <= First + precision) continue;
218         if(valknot >= Last - precision) break;
219         mySplitValues->InsertBefore(j++,valknot);
220       }
221       First = Last;
222     }
223     myNbCurves = mySplitValues->Length()-1;
224   }
225   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
226 }
227
228 //=======================================================================
229 //function : Build
230 //purpose  : 
231 //=======================================================================
232
233 void ShapeUpgrade_ConvertCurve2dToBezier::Build(const Standard_Boolean /*Segment*/)
234 {
235   Standard_Real prec = Precision::PConfusion();
236   Standard_Integer nb = mySplitValues->Length();
237   myResultingCurves =  new TColGeom2d_HArray1OfCurve (1,nb-1);
238   Standard_Real prevPar =0.;
239   Standard_Integer j=2;
240   for(Standard_Integer i = 2; i <= nb; i++) {
241     Standard_Real par = mySplitValues->Value(i);
242     for(; j<= mySplitParams->Length(); j++) 
243       if(mySplitParams->Value(j)+prec > par)
244         break;
245       else
246         prevPar = 0.;
247
248     Handle(Geom2d_BezierCurve) bes = Handle(Geom2d_BezierCurve)
249       ::DownCast(mySegments->Value(j-1)->Copy());
250     Standard_Real uFact = mySplitParams->Value(j) - mySplitParams->Value(j-1);
251     Standard_Real pp = mySplitValues->Value(i-1);
252     Standard_Real length = (par - pp)/uFact;
253     bes->Segment(prevPar, prevPar+length);
254     prevPar += length;
255     myResultingCurves->SetValue(i-1,bes);
256   }
257 }
258
259 //=======================================================================
260 //function : Segments
261 //purpose  : 
262 //=======================================================================
263
264 Handle(TColGeom2d_HSequenceOfCurve) ShapeUpgrade_ConvertCurve2dToBezier::Segments() const
265 {
266   return mySegments;
267 }
268
269 //=======================================================================
270 //function : SplitParams
271 //purpose  : 
272 //=======================================================================
273
274 Handle(TColStd_HSequenceOfReal) ShapeUpgrade_ConvertCurve2dToBezier::SplitParams() const
275 {
276   return mySplitParams;
277 }