d13c01e6e31b523673a27cab2e77276f4202cc12
[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 under
7 // the terms of the GNU Lesser General Public License 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 <AppCont_LeastSquare.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   myMaxSegments = IntegerLast();
54   alldone = Standard_False;
55   Perform(Line);
56 }
57
58 //=======================================================================
59 //function : Approx_ComputeCLine
60 //purpose  : Initializes the fields of the algorithm.
61 //=======================================================================
62
63 Approx_ComputeCLine::Approx_ComputeCLine
64 (const Standard_Integer degreemin,
65 const Standard_Integer degreemax,
66 const Standard_Real Tolerance3d,
67 const Standard_Real Tolerance2d,
68 const Standard_Boolean cutting,
69 const AppParCurves_Constraint FirstC,
70 const AppParCurves_Constraint LastC)
71 {
72   alldone = Standard_False;
73   mydegremin = degreemin;
74   mydegremax = degreemax;
75   mytol3d = Tolerance3d;
76   mytol2d = Tolerance2d;
77   mycut = cutting;
78   myfirstC = FirstC;
79   mylastC = LastC;
80   myMaxSegments = IntegerLast();
81 }
82
83 //=======================================================================
84 //function : Perform
85 //purpose  : runs the algorithm after having initialized the fields.
86 //=======================================================================
87
88 void Approx_ComputeCLine::Perform(const MultiLine& Line)
89 {
90   Standard_Real UFirst, ULast;
91   Standard_Boolean Finish = Standard_False,
92     begin = Standard_True, Ok = Standard_False;
93   Standard_Real thetol3d = Precision::Confusion(), thetol2d = Precision::Confusion();
94   UFirst = Line.FirstParameter();
95   ULast = Line.LastParameter();
96   Standard_Real TolU = Max((ULast - UFirst)*1.e-03, Precision::Confusion());
97   Standard_Real myfirstU = UFirst;
98   Standard_Real mylastU = ULast;
99   Standard_Integer aMaxSegments = 0;
100   Standard_Integer aMaxSegments1 = myMaxSegments - 1;
101   Standard_Integer aNbCut = 0, aNbImp = 0, aNbComp = 5;
102
103   if (!mycut)
104   {
105     alldone = Compute(Line, UFirst, ULast, thetol3d, thetol2d);
106     if (!alldone)
107     {
108       tolreached = Standard_False;
109       myfirstparam.Append(UFirst);
110       mylastparam.Append(ULast);
111       myMultiCurves.Append(TheMultiCurve);
112       Tolers3d.Append(currenttol3d);
113       Tolers2d.Append(currenttol2d);
114     }
115   }
116   else
117   {
118
119     // previous decision to be taken if we get worse with next cut (eap)
120     AppParCurves_MultiCurve KeptMultiCurve;
121     Standard_Real KeptUfirst = 0., KeptUlast = 0., KeptT3d = RealLast(), KeptT2d = 0.;
122
123     while (!Finish)
124     {
125
126       // Gestion du decoupage de la multiline pour approximer:
127       if (!begin)
128       {
129         if (Ok)
130         {
131           // Calcul de la partie a approximer.
132           myfirstU = mylastU;
133           mylastU = ULast;
134           aNbCut = 0;
135           aNbImp = 0;
136           if (Abs(ULast - myfirstU) <= RealEpsilon()
137               || aMaxSegments >= myMaxSegments)
138           {
139             Finish = Standard_True;
140             alldone = Standard_True;
141             return;
142           }
143           KeptT3d = RealLast(); KeptT2d = 0;
144           KeptUfirst = myfirstU;
145           KeptUlast = mylastU;
146         }
147         else
148         {
149           // keep best decison
150           if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d))
151           {
152             KeptMultiCurve = TheMultiCurve;
153             KeptUfirst = myfirstU;
154             KeptUlast = mylastU;
155             KeptT3d = thetol3d;
156             KeptT2d = thetol2d;
157             aNbImp++;
158           }
159
160           // cut an interval
161           mylastU = (myfirstU + mylastU) / 2;
162           aNbCut++;
163         }
164       }
165
166       // Calcul des parametres sur ce nouvel intervalle.
167       Ok = Compute(Line, myfirstU, mylastU, thetol3d, thetol2d);
168       if (Ok)
169       {
170         aMaxSegments++;
171       }
172
173       //cout << myfirstU << " - " << mylastU << "  tol : " << thetol3d << " " << thetol2d << endl;
174       Standard_Boolean aStopCutting = Standard_False;
175       if (aNbCut >= aNbComp)
176       {
177         if (aNbCut > aNbImp)
178         {
179           aStopCutting = Standard_True;
180         }
181       }
182       // is new decision better?
183       if (!Ok && (Abs(myfirstU - mylastU) <= TolU || aMaxSegments >= aMaxSegments1 || aStopCutting ))
184       {
185         Ok = Standard_True; // stop interval cutting, approx the rest part
186
187         if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d))
188         {
189           KeptMultiCurve = TheMultiCurve;
190           KeptUfirst = myfirstU;
191           KeptUlast = mylastU;
192           KeptT3d = thetol3d;
193           KeptT2d = thetol2d;
194         }
195
196         mylastU = KeptUlast;
197
198         tolreached = Standard_False; // helas
199         myMultiCurves.Append(KeptMultiCurve);
200         aMaxSegments++;
201         Tolers3d.Append(KeptT3d);
202         Tolers2d.Append(KeptT2d);
203         myfirstparam.Append(KeptUfirst);
204         mylastparam.Append(KeptUlast);
205       }
206
207       begin = Standard_False;
208     } // while (!Finish)
209   }
210 }
211
212 //=======================================================================
213 //function : NbMultiCurves
214 //purpose  : Returns the number of MultiCurve doing the approximation
215 //           of the MultiLine.
216 //=======================================================================
217
218 Standard_Integer Approx_ComputeCLine::NbMultiCurves()const
219 {
220   return myMultiCurves.Length();
221 }
222
223 //=======================================================================
224 //function : Value
225 //purpose  : returns the approximation MultiCurve of range <Index>.
226 //=======================================================================
227
228 AppParCurves_MultiCurve Approx_ComputeCLine::Value(const Standard_Integer Index)
229 const
230 {
231   return myMultiCurves.Value(Index);
232 }
233
234 //=======================================================================
235 //function : Compute
236 //purpose  : is internally used by the algorithms.
237 //=======================================================================
238
239 Standard_Boolean Approx_ComputeCLine::Compute(const MultiLine& Line,
240   const Standard_Real Ufirst,
241   const Standard_Real Ulast,
242   Standard_Real&   TheTol3d,
243   Standard_Real&   TheTol2d)
244 {
245
246
247   Standard_Integer deg, NbPoints = 24;
248   Standard_Boolean mydone;
249   Standard_Real Fv;
250
251   for (deg = mydegremin; deg <= mydegremax; deg++) {
252
253     AppCont_LeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC, deg, NbPoints);
254     mydone = LSquare.IsDone();
255     if (mydone) {
256       LSquare.Error(Fv, TheTol3d, TheTol2d);
257       if (TheTol3d <= mytol3d && TheTol2d <= mytol2d) {
258         // Stockage de la multicurve approximee.
259         tolreached = Standard_True;
260         myMultiCurves.Append(LSquare.Value());
261         myfirstparam.Append(Ufirst);
262         mylastparam.Append(Ulast);
263         Tolers3d.Append(TheTol3d);
264         Tolers2d.Append(TheTol2d);
265         return Standard_True;
266       }
267     }
268     if (deg == mydegremax) {
269       TheMultiCurve = LSquare.Value();
270       currenttol3d = TheTol3d;
271       currenttol2d = TheTol2d;
272     }
273
274   }
275   return Standard_False;
276 }
277
278 //=======================================================================
279 //function : Parameters
280 //purpose  : returns the first and last parameters of the 
281 //           <Index> MultiCurve.
282 //=======================================================================
283
284 void Approx_ComputeCLine::Parameters(const Standard_Integer Index,
285   Standard_Real& firstpar,
286   Standard_Real& lastpar) const
287 {
288   firstpar = myfirstparam.Value(Index);
289   lastpar = mylastparam.Value(Index);
290 }
291
292 //=======================================================================
293 //function : SetDegrees
294 //purpose  : changes the degrees of the approximation.
295 //=======================================================================
296
297 void Approx_ComputeCLine::SetDegrees(const Standard_Integer degreemin,
298   const Standard_Integer degreemax)
299 {
300   mydegremin = degreemin;
301   mydegremax = degreemax;
302 }
303
304 //=======================================================================
305 //function : SetTolerances
306 //purpose  : Changes the tolerances of the approximation.
307 //=======================================================================
308
309 void Approx_ComputeCLine::SetTolerances(const Standard_Real Tolerance3d,
310   const Standard_Real Tolerance2d)
311 {
312   mytol3d = Tolerance3d;
313   mytol2d = Tolerance2d;
314 }
315
316 //=======================================================================
317 //function : SetConstraints
318 //purpose  : Changes the constraints of the approximation.
319 //=======================================================================
320
321 void Approx_ComputeCLine::SetConstraints(const AppParCurves_Constraint FirstC,
322   const AppParCurves_Constraint LastC)
323 {
324   myfirstC = FirstC;
325   mylastC = LastC;
326 }
327
328 //=======================================================================
329 //function : SetMaxSegments
330 //purpose  : Changes the max number of segments, which is allowed for cutting.
331 //=======================================================================
332
333 void Approx_ComputeCLine::SetMaxSegments(const Standard_Integer theMaxSegments)
334 {
335   myMaxSegments = theMaxSegments;
336 }
337
338 //=======================================================================
339 //function : IsAllApproximated
340 //purpose  : returns False if at a moment of the approximation,
341 //           the status NoApproximation has been sent by the user
342 //           when more points were needed.
343 //=======================================================================
344
345 Standard_Boolean Approx_ComputeCLine::IsAllApproximated()
346 const {
347   return alldone;
348 }
349
350 //=======================================================================
351 //function : IsToleranceReached
352 //purpose  : returns False if the status NoPointsAdded has been sent.
353 //=======================================================================
354
355 Standard_Boolean Approx_ComputeCLine::IsToleranceReached()
356 const {
357   return tolreached;
358 }
359
360 //=======================================================================
361 //function : Error
362 //purpose  : returns the tolerances 2d and 3d of the <Index> MultiCurve.
363 //=======================================================================
364
365 void Approx_ComputeCLine::Error(const Standard_Integer Index,
366   Standard_Real& tol3d,
367   Standard_Real& tol2d) const
368 {
369   tol3d = Tolers3d.Value(Index);
370   tol2d = Tolers2d.Value(Index);
371 }