0030686: Visualization, SelectMgr_ViewerSelector - sorting issues of transformation...
[occt.git] / src / Approx / Approx_ComputeCLine.gxx
CommitLineData
b311480e 1// Copyright (c) 1995-1999 Matra Datavision
973c2be1 2// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 3//
973c2be1 4// This file is part of Open CASCADE Technology software library.
b311480e 5//
d5f74e42 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
973c2be1 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.
b311480e 11//
973c2be1 12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
7fd59977 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>
368cdde6 22#include <AppCont_LeastSquare.hxx>
7fd59977 23#include <TColStd_Array1OfReal.hxx>
24#include <AppParCurves_Constraint.hxx>
25#include <Approx_Status.hxx>
1d47d8d0 26#include <Precision.hxx>
7fd59977 27
ba7f665d 28const static Standard_Integer MAXSEGM = 1000;
29
7fd59977 30//=======================================================================
31//function : Approx_ComputeCLine
32//purpose : The MultiLine <Line> will be approximated until tolerances
33// will be reached.
34// The approximation will be done from degreemin to degreemax
35// with a cutting if the corresponding boolean is True.
36//=======================================================================
37
38Approx_ComputeCLine::Approx_ComputeCLine
afb3647b 39(const MultiLine& Line,
40const Standard_Integer degreemin,
41const Standard_Integer degreemax,
42const Standard_Real Tolerance3d,
43const Standard_Real Tolerance2d,
44const Standard_Boolean cutting,
45const AppParCurves_Constraint FirstC,
46const AppParCurves_Constraint LastC)
7fd59977 47{
48 mydegremin = degreemin;
49 mydegremax = degreemax;
50 mytol3d = Tolerance3d;
51 mytol2d = Tolerance2d;
52 mycut = cutting;
53 myfirstC = FirstC;
54 mylastC = LastC;
ba7f665d 55 myMaxSegments = MAXSEGM;
56 myInvOrder = Standard_True;
7fd59977 57 alldone = Standard_False;
58 Perform(Line);
59}
60
61//=======================================================================
62//function : Approx_ComputeCLine
63//purpose : Initializes the fields of the algorithm.
64//=======================================================================
65
66Approx_ComputeCLine::Approx_ComputeCLine
afb3647b 67(const Standard_Integer degreemin,
68const Standard_Integer degreemax,
69const Standard_Real Tolerance3d,
70const Standard_Real Tolerance2d,
71const Standard_Boolean cutting,
72const AppParCurves_Constraint FirstC,
73const AppParCurves_Constraint LastC)
7fd59977 74{
75 alldone = Standard_False;
76 mydegremin = degreemin;
77 mydegremax = degreemax;
78 mytol3d = Tolerance3d;
79 mytol2d = Tolerance2d;
80 mycut = cutting;
81 myfirstC = FirstC;
82 mylastC = LastC;
ba7f665d 83 myMaxSegments = MAXSEGM;
84 myInvOrder = Standard_True;
7fd59977 85}
86
87//=======================================================================
88//function : Perform
89//purpose : runs the algorithm after having initialized the fields.
90//=======================================================================
91
92void Approx_ComputeCLine::Perform(const MultiLine& Line)
93{
7fd59977 94 Standard_Real UFirst, ULast;
afb3647b 95 Standard_Boolean Finish = Standard_False,
96 begin = Standard_True, Ok = Standard_False;
1d47d8d0 97 Standard_Real thetol3d = Precision::Confusion(), thetol2d = Precision::Confusion();
368cdde6 98 UFirst = Line.FirstParameter();
afb3647b 99 ULast = Line.LastParameter();
100 Standard_Real TolU = Max((ULast - UFirst)*1.e-03, Precision::Confusion());
101 Standard_Real myfirstU = UFirst;
7fd59977 102 Standard_Real mylastU = ULast;
f998596a 103 Standard_Integer aMaxSegments = 0;
104 Standard_Integer aMaxSegments1 = myMaxSegments - 1;
afb3647b 105 Standard_Integer aNbCut = 0, aNbImp = 0, aNbComp = 5;
7fd59977 106
7da00517 107 if (!mycut)
108 {
7fd59977 109 alldone = Compute(Line, UFirst, ULast, thetol3d, thetol2d);
afb3647b 110 if (!alldone)
7da00517 111 {
7fd59977 112 tolreached = Standard_False;
113 myfirstparam.Append(UFirst);
114 mylastparam.Append(ULast);
115 myMultiCurves.Append(TheMultiCurve);
116 Tolers3d.Append(currenttol3d);
117 Tolers2d.Append(currenttol2d);
118 }
119 }
afb3647b 120 else
7da00517 121 {
7fd59977 122
123 // previous decision to be taken if we get worse with next cut (eap)
124 AppParCurves_MultiCurve KeptMultiCurve;
1d47d8d0 125 Standard_Real KeptUfirst = 0., KeptUlast = 0., KeptT3d = RealLast(), KeptT2d = 0.;
1d47d8d0 126
afb3647b 127 while (!Finish)
7da00517 128 {
afb3647b 129
7fd59977 130 // Gestion du decoupage de la multiline pour approximer:
afb3647b 131 if (!begin)
7da00517 132 {
afb3647b 133 if (Ok)
7da00517 134 {
135 // Calcul de la partie a approximer.
136 myfirstU = mylastU;
afb3647b 137 mylastU = ULast;
138 aNbCut = 0;
139 aNbImp = 0;
140 if (Abs(ULast - myfirstU) <= RealEpsilon()
f998596a 141 || aMaxSegments >= myMaxSegments)
7da00517 142 {
143 Finish = Standard_True;
144 alldone = Standard_True;
145 return;
146 }
147 KeptT3d = RealLast(); KeptT2d = 0;
148 KeptUfirst = myfirstU;
149 KeptUlast = mylastU;
150 }
151 else
152 {
153 // keep best decison
154 if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d))
155 {
156 KeptMultiCurve = TheMultiCurve;
afb3647b 157 KeptUfirst = myfirstU;
158 KeptUlast = mylastU;
159 KeptT3d = thetol3d;
160 KeptT2d = thetol2d;
161 aNbImp++;
7da00517 162 }
163
164 // cut an interval
afb3647b 165 mylastU = (myfirstU + mylastU) / 2;
166 aNbCut++;
7da00517 167 }
7fd59977 168 }
169
7fd59977 170 // Calcul des parametres sur ce nouvel intervalle.
171 Ok = Compute(Line, myfirstU, mylastU, thetol3d, thetol2d);
afb3647b 172 if (Ok)
f998596a 173 {
174 aMaxSegments++;
175 }
7fd59977 176
177 //cout << myfirstU << " - " << mylastU << " tol : " << thetol3d << " " << thetol2d << endl;
afb3647b 178 Standard_Boolean aStopCutting = Standard_False;
179 if (aNbCut >= aNbComp)
180 {
181 if (aNbCut > aNbImp)
182 {
183 aStopCutting = Standard_True;
184 }
185 }
7fd59977 186 // is new decision better?
afb3647b 187 if (!Ok && (Abs(myfirstU - mylastU) <= TolU || aMaxSegments >= aMaxSegments1 || aStopCutting ))
7fd59977 188 {
afb3647b 189 Ok = Standard_True; // stop interval cutting, approx the rest part
3629864d 190
afb3647b 191 if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d))
192 {
193 KeptMultiCurve = TheMultiCurve;
194 KeptUfirst = myfirstU;
195 KeptUlast = mylastU;
196 KeptT3d = thetol3d;
197 KeptT2d = thetol2d;
198 }
3629864d 199
afb3647b 200 mylastU = KeptUlast;
7da00517 201
afb3647b 202 tolreached = Standard_False; // helas
203 myMultiCurves.Append(KeptMultiCurve);
204 aMaxSegments++;
205 Tolers3d.Append(KeptT3d);
206 Tolers2d.Append(KeptT2d);
207 myfirstparam.Append(KeptUfirst);
208 mylastparam.Append(KeptUlast);
209 }
7fd59977 210
211 begin = Standard_False;
212 } // while (!Finish)
213 }
214}
215
216//=======================================================================
217//function : NbMultiCurves
218//purpose : Returns the number of MultiCurve doing the approximation
219// of the MultiLine.
220//=======================================================================
221
222Standard_Integer Approx_ComputeCLine::NbMultiCurves()const
223{
224 return myMultiCurves.Length();
225}
226
227//=======================================================================
228//function : Value
229//purpose : returns the approximation MultiCurve of range <Index>.
230//=======================================================================
231
232AppParCurves_MultiCurve Approx_ComputeCLine::Value(const Standard_Integer Index)
233const
234{
235 return myMultiCurves.Value(Index);
236}
237
238//=======================================================================
239//function : Compute
240//purpose : is internally used by the algorithms.
241//=======================================================================
242
243Standard_Boolean Approx_ComputeCLine::Compute(const MultiLine& Line,
afb3647b 244 const Standard_Real Ufirst,
245 const Standard_Real Ulast,
246 Standard_Real& TheTol3d,
247 Standard_Real& TheTol2d)
7fd59977 248{
249
250
ba7f665d 251 const Standard_Integer NbPointsMax = 24;
252 const Standard_Real aMinRatio = 0.05;
253 const Standard_Integer aMaxDeg = 8;
254 //
255 Standard_Integer deg, NbPoints;
7fd59977 256 Standard_Boolean mydone;
257 Standard_Real Fv;
258
ba7f665d 259 AppParCurves_MultiCurve aPrevCurve;
260 Standard_Real aPrevTol3d = RealLast(), aPrevTol2d = RealLast();
261 Standard_Boolean aPrevIsOk = Standard_False;
262 Standard_Boolean anInvOrder = myInvOrder;
263 if (anInvOrder && mydegremax > aMaxDeg)
264 {
265 if ((Ulast - Ufirst) / (Line.LastParameter() - Line.FirstParameter()) < aMinRatio)
266 {
267 anInvOrder = Standard_False;
268 }
269 }
270 if (anInvOrder)
271 {
272 for (deg = mydegremax; deg >= mydegremin; deg--) {
273 NbPoints = Min(2 * deg + 1, NbPointsMax);
274 AppCont_LeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC, deg, NbPoints);
275 mydone = LSquare.IsDone();
276 if (mydone)
277 {
278 LSquare.Error(Fv, TheTol3d, TheTol2d);
279 if (TheTol3d <= mytol3d && TheTol2d <= mytol2d)
280 {
281 if (deg == mydegremin)
282 {
283 // Stockage de la multicurve approximee.
284 tolreached = Standard_True;
285 myMultiCurves.Append(LSquare.Value());
286 myfirstparam.Append(Ufirst);
287 mylastparam.Append(Ulast);
288 Tolers3d.Append(TheTol3d);
289 Tolers2d.Append(TheTol2d);
290 return Standard_True;
291 }
292 aPrevTol3d = TheTol3d;
293 aPrevTol2d = TheTol2d;
294 aPrevCurve = LSquare.Value();
295 aPrevIsOk = Standard_True;
296 continue;
297 }
298 else if (aPrevIsOk)
299 {
300 // Stockage de la multicurve approximee.
301 tolreached = Standard_True;
302 TheTol3d = aPrevTol3d;
303 TheTol2d = aPrevTol2d;
304 myMultiCurves.Append(aPrevCurve);
305 myfirstparam.Append(Ufirst);
306 mylastparam.Append(Ulast);
307 Tolers3d.Append(aPrevTol3d);
308 Tolers2d.Append(aPrevTol2d);
309 return Standard_True;
310 }
311 }
312 else if (aPrevIsOk)
313 {
afb3647b 314 // Stockage de la multicurve approximee.
315 tolreached = Standard_True;
ba7f665d 316 TheTol3d = aPrevTol3d;
317 TheTol2d = aPrevTol2d;
318 myMultiCurves.Append(aPrevCurve);
afb3647b 319 myfirstparam.Append(Ufirst);
320 mylastparam.Append(Ulast);
ba7f665d 321 Tolers3d.Append(aPrevTol3d);
322 Tolers2d.Append(aPrevTol2d);
afb3647b 323 return Standard_True;
7fd59977 324 }
ba7f665d 325 if (!aPrevIsOk && deg == mydegremax)
326 {
327 TheMultiCurve = LSquare.Value();
328 currenttol3d = TheTol3d;
329 currenttol2d = TheTol2d;
330 aPrevTol3d = TheTol3d;
331 aPrevTol2d = TheTol2d;
332 aPrevCurve = TheMultiCurve;
333 break;
334 }
7fd59977 335 }
ba7f665d 336 }
337 else
338 {
339 for (deg = mydegremin; deg <= mydegremax; deg++) {
340 NbPoints = Min(2 * deg + 1, NbPointsMax);
341 AppCont_LeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC, deg, NbPoints);
342 mydone = LSquare.IsDone();
343 if (mydone) {
344 LSquare.Error(Fv, TheTol3d, TheTol2d);
345 if (TheTol3d <= mytol3d && TheTol2d <= mytol2d) {
346 // Stockage de la multicurve approximee.
347 tolreached = Standard_True;
348 myMultiCurves.Append(LSquare.Value());
349 myfirstparam.Append(Ufirst);
350 mylastparam.Append(Ulast);
351 Tolers3d.Append(TheTol3d);
352 Tolers2d.Append(TheTol2d);
353 return Standard_True;
354 }
355 }
356 if (deg == mydegremax) {
357 TheMultiCurve = LSquare.Value();
358 currenttol3d = TheTol3d;
359 currenttol2d = TheTol2d;
360 }
7fd59977 361 }
7fd59977 362 }
363 return Standard_False;
364}
365
366//=======================================================================
367//function : Parameters
368//purpose : returns the first and last parameters of the
369// <Index> MultiCurve.
370//=======================================================================
371
372void Approx_ComputeCLine::Parameters(const Standard_Integer Index,
afb3647b 373 Standard_Real& firstpar,
374 Standard_Real& lastpar) const
7fd59977 375{
376 firstpar = myfirstparam.Value(Index);
afb3647b 377 lastpar = mylastparam.Value(Index);
7fd59977 378}
379
380//=======================================================================
381//function : SetDegrees
382//purpose : changes the degrees of the approximation.
383//=======================================================================
384
385void Approx_ComputeCLine::SetDegrees(const Standard_Integer degreemin,
afb3647b 386 const Standard_Integer degreemax)
7fd59977 387{
388 mydegremin = degreemin;
389 mydegremax = degreemax;
390}
391
392//=======================================================================
393//function : SetTolerances
394//purpose : Changes the tolerances of the approximation.
395//=======================================================================
396
397void Approx_ComputeCLine::SetTolerances(const Standard_Real Tolerance3d,
afb3647b 398 const Standard_Real Tolerance2d)
7fd59977 399{
400 mytol3d = Tolerance3d;
401 mytol2d = Tolerance2d;
402}
403
404//=======================================================================
405//function : SetConstraints
406//purpose : Changes the constraints of the approximation.
407//=======================================================================
408
409void Approx_ComputeCLine::SetConstraints(const AppParCurves_Constraint FirstC,
afb3647b 410 const AppParCurves_Constraint LastC)
7fd59977 411{
412 myfirstC = FirstC;
afb3647b 413 mylastC = LastC;
7fd59977 414}
415
f998596a 416//=======================================================================
417//function : SetMaxSegments
418//purpose : Changes the max number of segments, which is allowed for cutting.
419//=======================================================================
420
afb3647b 421void Approx_ComputeCLine::SetMaxSegments(const Standard_Integer theMaxSegments)
f998596a 422{
423 myMaxSegments = theMaxSegments;
424}
425
ba7f665d 426//=======================================================================
427//function : SetInvOrder
428//purpose :
429//=======================================================================
430void Approx_ComputeCLine::SetInvOrder(const Standard_Boolean theInvOrder)
431{
432 myInvOrder = theInvOrder;
433}
434
7fd59977 435//=======================================================================
436//function : IsAllApproximated
437//purpose : returns False if at a moment of the approximation,
438// the status NoApproximation has been sent by the user
439// when more points were needed.
440//=======================================================================
441
442Standard_Boolean Approx_ComputeCLine::IsAllApproximated()
443const {
444 return alldone;
445}
446
447//=======================================================================
448//function : IsToleranceReached
449//purpose : returns False if the status NoPointsAdded has been sent.
450//=======================================================================
451
452Standard_Boolean Approx_ComputeCLine::IsToleranceReached()
453const {
454 return tolreached;
455}
456
457//=======================================================================
458//function : Error
459//purpose : returns the tolerances 2d and 3d of the <Index> MultiCurve.
460//=======================================================================
461
462void Approx_ComputeCLine::Error(const Standard_Integer Index,
afb3647b 463 Standard_Real& tol3d,
464 Standard_Real& tol2d) const
7fd59977 465{
466 tol3d = Tolers3d.Value(Index);
467 tol2d = Tolers2d.Value(Index);
468}