c5db0b726a7e01f9da2b14d5f1967a320f750eb5
[occt.git] / src / Approx / Approx_ComputeCLine.gxx
1 // Copyright (c) 1995-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and / or modify it
7 // under the terms of the GNU Lesser General Public version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 //  modified by Edward AGAPOV (eap) Tue Apr 2 2002 (occ265)
16 //  -- stop cutting an interval to approximate if next decisions
17 //  -- get worse on and on
18
19
20
21 #include <Approx_ParametrizationType.hxx>
22 #include Approx_MyLeastSquare_hxx
23 #include <TColStd_Array1OfReal.hxx>
24 #include <AppParCurves_Constraint.hxx>
25 #include <Approx_Status.hxx>
26 #include <Precision.hxx>
27
28 //=======================================================================
29 //function : Approx_ComputeCLine
30 //purpose  : The MultiLine <Line> will be approximated until tolerances
31 //           will be reached.
32 //           The approximation will be done from degreemin to degreemax
33 //           with a cutting if the corresponding boolean is True.
34 //=======================================================================
35
36 Approx_ComputeCLine::Approx_ComputeCLine
37                     (const MultiLine& Line,
38                      const Standard_Integer degreemin,
39                      const Standard_Integer degreemax,
40                      const Standard_Real Tolerance3d,
41                      const Standard_Real Tolerance2d,
42                      const Standard_Boolean cutting,
43                      const AppParCurves_Constraint FirstC,
44                      const AppParCurves_Constraint LastC)
45 {
46   mydegremin = degreemin;
47   mydegremax = degreemax;
48   mytol3d = Tolerance3d;
49   mytol2d = Tolerance2d;
50   mycut = cutting;
51   myfirstC = FirstC;
52   mylastC = LastC;
53   alldone = Standard_False;
54   Perform(Line);
55 }
56
57 //=======================================================================
58 //function : Approx_ComputeCLine
59 //purpose  : Initializes the fields of the algorithm.
60 //=======================================================================
61
62 Approx_ComputeCLine::Approx_ComputeCLine
63                     (const Standard_Integer degreemin,
64                      const Standard_Integer degreemax,
65                      const Standard_Real Tolerance3d,
66                      const Standard_Real Tolerance2d,
67                      const Standard_Boolean cutting,
68                      const AppParCurves_Constraint FirstC,
69                      const AppParCurves_Constraint LastC)
70 {
71   alldone = Standard_False;
72   mydegremin = degreemin;
73   mydegremax = degreemax;
74   mytol3d = Tolerance3d;
75   mytol2d = Tolerance2d;
76   mycut = cutting;
77   myfirstC = FirstC;
78   mylastC = LastC;
79 }
80
81 //=======================================================================
82 //function : Perform
83 //purpose  : runs the algorithm after having initialized the fields.
84 //=======================================================================
85
86 void Approx_ComputeCLine::Perform(const MultiLine& Line)
87 {
88   Standard_Real UFirst, ULast;
89   Standard_Boolean Finish = Standard_False, 
90           begin = Standard_True, Ok = Standard_False;
91   Standard_Real thetol3d = Precision::Confusion(), thetol2d = Precision::Confusion();
92   UFirst = LineTool::FirstParameter(Line);
93   ULast  = LineTool::LastParameter(Line);
94   Standard_Real TolU = (ULast-UFirst)*1.e-05;
95   Standard_Real myfirstU = UFirst; 
96   Standard_Real mylastU = ULast;
97
98   if (!mycut) {
99     alldone = Compute(Line, UFirst, ULast, thetol3d, thetol2d);
100     if (!alldone) {
101       tolreached = Standard_False;
102       myfirstparam.Append(UFirst);
103       mylastparam.Append(ULast);
104       myMultiCurves.Append(TheMultiCurve);
105       Tolers3d.Append(currenttol3d);
106       Tolers2d.Append(currenttol2d);
107     }
108   }
109   else {
110
111     // previous decision to be taken if we get worse with next cut (eap)
112     AppParCurves_MultiCurve KeptMultiCurve;
113     Standard_Real KeptUfirst = 0., KeptUlast = 0., KeptT3d = RealLast(), KeptT2d = 0.;
114     Standard_Integer NbWorseDecis = 0, NbAllowedBadDecis = 10;
115
116     while (!Finish) {
117       
118       // Gestion du decoupage de la multiline pour approximer:
119       if (!begin) {
120         if (Ok) {
121           // Calcul de la partie a approximer.
122           myfirstU = mylastU;
123           mylastU  = ULast;
124           if (Abs(ULast-myfirstU) <= RealEpsilon()) {
125             Finish = Standard_True;
126             alldone = Standard_True;
127             return;
128           }
129           KeptT3d = RealLast(); KeptT2d = 0; 
130           NbWorseDecis = 0;
131         }
132         else {
133           // keep best decison
134           if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d)) {
135             KeptMultiCurve = TheMultiCurve;
136             KeptUfirst     = myfirstU;
137             KeptUlast      = mylastU;
138             KeptT3d        = thetol3d;
139             KeptT2d        = thetol2d;
140           }
141           
142           // cut an interval
143           mylastU = (myfirstU + mylastU)/2;
144         }
145       }
146
147       if (Abs(myfirstU-mylastU) <= TolU) /*break;*/ // pour ne pas planter
148         NbAllowedBadDecis /= 2;                     // la station.
149       
150       // Calcul des parametres sur ce nouvel intervalle.
151       Ok = Compute(Line, myfirstU, mylastU, thetol3d, thetol2d);
152
153       //cout << myfirstU << " - " << mylastU << "  tol : " << thetol3d << " " << thetol2d << endl;
154
155       // is new decision better?
156       if ( !Ok && (thetol3d + thetol2d) > (KeptT3d + KeptT2d) )
157       {
158         NbWorseDecis++;
159
160         if (NbWorseDecis > NbAllowedBadDecis) {
161           
162           Ok = Standard_True; // stop interval cutting, approx the rest part
163           mylastU = KeptUlast;
164           
165           tolreached = Standard_False; // helas
166           myMultiCurves.Append(KeptMultiCurve);
167           Tolers3d.Append     (KeptT3d);
168           Tolers2d.Append     (KeptT2d);
169           myfirstparam.Append (KeptUfirst);
170           mylastparam.Append  (KeptUlast);
171         }
172       }
173
174       begin = Standard_False;
175     } // while (!Finish)
176   }
177 }
178
179 //=======================================================================
180 //function : NbMultiCurves
181 //purpose  : Returns the number of MultiCurve doing the approximation
182 //           of the MultiLine.
183 //=======================================================================
184
185 Standard_Integer Approx_ComputeCLine::NbMultiCurves()const
186 {
187   return myMultiCurves.Length();
188 }
189
190 //=======================================================================
191 //function : Value
192 //purpose  : returns the approximation MultiCurve of range <Index>.
193 //=======================================================================
194
195 AppParCurves_MultiCurve Approx_ComputeCLine::Value(const Standard_Integer Index)
196 const
197 {
198   return myMultiCurves.Value(Index);
199 }
200
201 //=======================================================================
202 //function : Compute
203 //purpose  : is internally used by the algorithms.
204 //=======================================================================
205
206 Standard_Boolean Approx_ComputeCLine::Compute(const MultiLine& Line,
207                                              const Standard_Real Ufirst,
208                                              const Standard_Real Ulast,
209                                              Standard_Real&   TheTol3d,
210                                              Standard_Real&   TheTol2d)
211 {
212
213
214   Standard_Integer deg, NbPoints = 24;
215   Standard_Boolean mydone;
216   Standard_Real Fv;
217
218   for (deg = mydegremin; deg <= mydegremax; deg++) {
219
220     AppParCurves_MultiCurve mySCU(deg+1);
221     Approx_MyLeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC, 
222                                  deg, NbPoints);
223     mydone = LSquare.IsDone();
224     if (mydone) {
225       LSquare.Error(Fv, TheTol3d, TheTol2d);
226       if (TheTol3d <= mytol3d && TheTol2d <= mytol2d) {
227         mySCU = LSquare.Value();
228         // Stockage de la multicurve approximee.
229         tolreached = Standard_True;
230         myMultiCurves.Append(mySCU);
231         myfirstparam.Append(Ufirst);
232         mylastparam.Append(Ulast);
233         Tolers3d.Append(TheTol3d);
234         Tolers2d.Append(TheTol2d);
235         return Standard_True;
236       }
237     }
238     if (deg == mydegremax) {
239       TheMultiCurve = LSquare.Value();
240       currenttol3d = TheTol3d;
241       currenttol2d = TheTol2d;
242     }
243     
244   }
245   return Standard_False;
246 }
247
248 //=======================================================================
249 //function : Parameters
250 //purpose  : returns the first and last parameters of the 
251 //           <Index> MultiCurve.
252 //=======================================================================
253
254 void Approx_ComputeCLine::Parameters(const Standard_Integer Index,
255                                      Standard_Real& firstpar,
256                                      Standard_Real& lastpar) const
257 {
258   firstpar = myfirstparam.Value(Index);
259   lastpar  = mylastparam.Value(Index);
260 }
261
262 //=======================================================================
263 //function : SetDegrees
264 //purpose  : changes the degrees of the approximation.
265 //=======================================================================
266
267 void Approx_ComputeCLine::SetDegrees(const Standard_Integer degreemin,
268                                      const Standard_Integer degreemax)
269 {
270   mydegremin = degreemin;
271   mydegremax = degreemax;
272 }
273
274 //=======================================================================
275 //function : SetTolerances
276 //purpose  : Changes the tolerances of the approximation.
277 //=======================================================================
278
279 void Approx_ComputeCLine::SetTolerances(const Standard_Real Tolerance3d,
280                                        const Standard_Real Tolerance2d)
281 {
282   mytol3d = Tolerance3d;
283   mytol2d = Tolerance2d;
284 }
285
286 //=======================================================================
287 //function : SetConstraints
288 //purpose  : Changes the constraints of the approximation.
289 //=======================================================================
290
291 void Approx_ComputeCLine::SetConstraints(const AppParCurves_Constraint FirstC,
292                                          const AppParCurves_Constraint LastC)
293 {
294   myfirstC = FirstC;
295   mylastC  = LastC;
296 }
297
298 //=======================================================================
299 //function : IsAllApproximated
300 //purpose  : returns False if at a moment of the approximation,
301 //           the status NoApproximation has been sent by the user
302 //           when more points were needed.
303 //=======================================================================
304
305 Standard_Boolean Approx_ComputeCLine::IsAllApproximated()
306 const {
307   return alldone;
308 }
309
310 //=======================================================================
311 //function : IsToleranceReached
312 //purpose  : returns False if the status NoPointsAdded has been sent.
313 //=======================================================================
314
315 Standard_Boolean Approx_ComputeCLine::IsToleranceReached()
316 const {
317   return tolreached;
318 }
319
320 //=======================================================================
321 //function : Error
322 //purpose  : returns the tolerances 2d and 3d of the <Index> MultiCurve.
323 //=======================================================================
324
325 void Approx_ComputeCLine::Error(const Standard_Integer Index,
326                                Standard_Real& tol3d,
327                                Standard_Real& tol2d) const
328 {
329   tol3d = Tolers3d.Value(Index);
330   tol2d = Tolers2d.Value(Index);
331 }