1 // Copyright (c) 1995-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
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.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
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
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>
28 const static Standard_Integer MAXSEGM = 1000;
30 //=======================================================================
31 //function : Approx_ComputeCLine
32 //purpose : The MultiLine <Line> will be approximated until tolerances
34 // The approximation will be done from degreemin to degreemax
35 // with a cutting if the corresponding boolean is True.
36 //=======================================================================
38 Approx_ComputeCLine::Approx_ComputeCLine
39 (const MultiLine& Line,
40 const Standard_Integer degreemin,
41 const Standard_Integer degreemax,
42 const Standard_Real Tolerance3d,
43 const Standard_Real Tolerance2d,
44 const Standard_Boolean cutting,
45 const AppParCurves_Constraint FirstC,
46 const AppParCurves_Constraint LastC)
48 mydegremin = degreemin;
49 mydegremax = degreemax;
50 mytol3d = Tolerance3d;
51 mytol2d = Tolerance2d;
55 myMaxSegments = MAXSEGM;
56 myInvOrder = Standard_True;
57 alldone = Standard_False;
61 //=======================================================================
62 //function : Approx_ComputeCLine
63 //purpose : Initializes the fields of the algorithm.
64 //=======================================================================
66 Approx_ComputeCLine::Approx_ComputeCLine
67 (const Standard_Integer degreemin,
68 const Standard_Integer degreemax,
69 const Standard_Real Tolerance3d,
70 const Standard_Real Tolerance2d,
71 const Standard_Boolean cutting,
72 const AppParCurves_Constraint FirstC,
73 const AppParCurves_Constraint LastC)
75 alldone = Standard_False;
76 mydegremin = degreemin;
77 mydegremax = degreemax;
78 mytol3d = Tolerance3d;
79 mytol2d = Tolerance2d;
83 myMaxSegments = MAXSEGM;
84 myInvOrder = Standard_True;
87 //=======================================================================
89 //purpose : runs the algorithm after having initialized the fields.
90 //=======================================================================
92 void Approx_ComputeCLine::Perform(const MultiLine& Line)
94 Standard_Real UFirst, ULast;
95 Standard_Boolean Finish = Standard_False,
96 begin = Standard_True, Ok = Standard_False;
97 Standard_Real thetol3d = Precision::Confusion(), thetol2d = Precision::Confusion();
98 UFirst = Line.FirstParameter();
99 ULast = Line.LastParameter();
100 Standard_Real TolU = Max((ULast - UFirst)*1.e-03, Precision::Confusion());
101 Standard_Real myfirstU = UFirst;
102 Standard_Real mylastU = ULast;
103 Standard_Integer aMaxSegments = 0;
104 Standard_Integer aMaxSegments1 = myMaxSegments - 1;
105 Standard_Integer aNbCut = 0, aNbImp = 0, aNbComp = 10;
109 alldone = Compute(Line, UFirst, ULast, thetol3d, thetol2d);
112 tolreached = Standard_False;
113 myfirstparam.Append(UFirst);
114 mylastparam.Append(ULast);
115 myMultiCurves.Append(TheMultiCurve);
116 Tolers3d.Append(currenttol3d);
117 Tolers2d.Append(currenttol2d);
123 // previous decision to be taken if we get worse with next cut (eap)
124 AppParCurves_MultiCurve KeptMultiCurve;
125 Standard_Real KeptUfirst = 0., KeptUlast = 0., KeptT3d = RealLast(), KeptT2d = 0.;
130 // Gestion du decoupage de la multiline pour approximer:
135 // Calcul de la partie a approximer.
140 if (Abs(ULast - myfirstU) <= RealEpsilon()
141 || aMaxSegments >= myMaxSegments)
143 Finish = Standard_True;
144 alldone = Standard_True;
147 KeptT3d = RealLast(); KeptT2d = 0;
148 KeptUfirst = myfirstU;
154 if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d))
156 KeptMultiCurve = TheMultiCurve;
157 KeptUfirst = myfirstU;
165 mylastU = (myfirstU + mylastU) / 2;
170 // Calcul des parametres sur ce nouvel intervalle.
171 Ok = Compute(Line, myfirstU, mylastU, thetol3d, thetol2d);
177 //cout << myfirstU << " - " << mylastU << " tol : " << thetol3d << " " << thetol2d << endl;
178 Standard_Boolean aStopCutting = Standard_False;
179 if (aNbCut >= aNbComp)
181 if (aNbCut > aNbImp + 1)
183 aStopCutting = Standard_True;
188 // is new decision better?
189 if (!Ok && (Abs(myfirstU - mylastU) <= TolU || aMaxSegments >= aMaxSegments1 || aStopCutting ))
191 Ok = Standard_True; // stop interval cutting, approx the rest part
193 if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d))
195 KeptMultiCurve = TheMultiCurve;
196 KeptUfirst = myfirstU;
204 tolreached = Standard_False; // helas
205 myMultiCurves.Append(KeptMultiCurve);
207 Tolers3d.Append(KeptT3d);
208 Tolers2d.Append(KeptT2d);
209 myfirstparam.Append(KeptUfirst);
210 mylastparam.Append(KeptUlast);
213 begin = Standard_False;
218 //=======================================================================
219 //function : NbMultiCurves
220 //purpose : Returns the number of MultiCurve doing the approximation
222 //=======================================================================
224 Standard_Integer Approx_ComputeCLine::NbMultiCurves()const
226 return myMultiCurves.Length();
229 //=======================================================================
231 //purpose : returns the approximation MultiCurve of range <Index>.
232 //=======================================================================
234 AppParCurves_MultiCurve Approx_ComputeCLine::Value(const Standard_Integer Index)
237 return myMultiCurves.Value(Index);
240 //=======================================================================
242 //purpose : is internally used by the algorithms.
243 //=======================================================================
245 Standard_Boolean Approx_ComputeCLine::Compute(const MultiLine& Line,
246 const Standard_Real Ufirst,
247 const Standard_Real Ulast,
248 Standard_Real& TheTol3d,
249 Standard_Real& TheTol2d)
253 const Standard_Integer NbPointsMax = 24;
254 const Standard_Real aMinRatio = 0.05;
255 const Standard_Integer aMaxDeg = 8;
257 Standard_Integer deg, NbPoints;
258 Standard_Boolean mydone;
261 AppParCurves_MultiCurve aPrevCurve;
262 Standard_Real aPrevTol3d = RealLast(), aPrevTol2d = RealLast();
263 Standard_Boolean aPrevIsOk = Standard_False;
264 Standard_Boolean anInvOrder = myInvOrder;
265 if (anInvOrder && mydegremax > aMaxDeg)
267 if ((Ulast - Ufirst) / (Line.LastParameter() - Line.FirstParameter()) < aMinRatio)
269 anInvOrder = Standard_False;
274 for (deg = mydegremax; deg >= mydegremin; deg--) {
275 NbPoints = Min(2 * deg + 1, NbPointsMax);
276 AppCont_LeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC, deg, NbPoints);
277 mydone = LSquare.IsDone();
280 LSquare.Error(Fv, TheTol3d, TheTol2d);
281 if (TheTol3d <= mytol3d && TheTol2d <= mytol2d)
283 if (deg == mydegremin)
285 // Stockage de la multicurve approximee.
286 tolreached = Standard_True;
287 myMultiCurves.Append(LSquare.Value());
288 myfirstparam.Append(Ufirst);
289 mylastparam.Append(Ulast);
290 Tolers3d.Append(TheTol3d);
291 Tolers2d.Append(TheTol2d);
292 return Standard_True;
294 aPrevTol3d = TheTol3d;
295 aPrevTol2d = TheTol2d;
296 aPrevCurve = LSquare.Value();
297 aPrevIsOk = Standard_True;
302 // Stockage de la multicurve approximee.
303 tolreached = Standard_True;
304 TheTol3d = aPrevTol3d;
305 TheTol2d = aPrevTol2d;
306 myMultiCurves.Append(aPrevCurve);
307 myfirstparam.Append(Ufirst);
308 mylastparam.Append(Ulast);
309 Tolers3d.Append(aPrevTol3d);
310 Tolers2d.Append(aPrevTol2d);
311 return Standard_True;
316 // Stockage de la multicurve approximee.
317 tolreached = Standard_True;
318 TheTol3d = aPrevTol3d;
319 TheTol2d = aPrevTol2d;
320 myMultiCurves.Append(aPrevCurve);
321 myfirstparam.Append(Ufirst);
322 mylastparam.Append(Ulast);
323 Tolers3d.Append(aPrevTol3d);
324 Tolers2d.Append(aPrevTol2d);
325 return Standard_True;
327 if (!aPrevIsOk && deg == mydegremax)
329 TheMultiCurve = LSquare.Value();
330 currenttol3d = TheTol3d;
331 currenttol2d = TheTol2d;
332 aPrevTol3d = TheTol3d;
333 aPrevTol2d = TheTol2d;
334 aPrevCurve = TheMultiCurve;
341 for (deg = mydegremin; deg <= mydegremax; deg++) {
342 NbPoints = Min(2 * deg + 1, NbPointsMax);
343 AppCont_LeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC, deg, NbPoints);
344 mydone = LSquare.IsDone();
346 LSquare.Error(Fv, TheTol3d, TheTol2d);
347 if (TheTol3d <= mytol3d && TheTol2d <= mytol2d) {
348 // Stockage de la multicurve approximee.
349 tolreached = Standard_True;
350 myMultiCurves.Append(LSquare.Value());
351 myfirstparam.Append(Ufirst);
352 mylastparam.Append(Ulast);
353 Tolers3d.Append(TheTol3d);
354 Tolers2d.Append(TheTol2d);
355 return Standard_True;
358 if (deg == mydegremax) {
359 TheMultiCurve = LSquare.Value();
360 currenttol3d = TheTol3d;
361 currenttol2d = TheTol2d;
365 return Standard_False;
368 //=======================================================================
369 //function : Parameters
370 //purpose : returns the first and last parameters of the
371 // <Index> MultiCurve.
372 //=======================================================================
374 void Approx_ComputeCLine::Parameters(const Standard_Integer Index,
375 Standard_Real& firstpar,
376 Standard_Real& lastpar) const
378 firstpar = myfirstparam.Value(Index);
379 lastpar = mylastparam.Value(Index);
382 //=======================================================================
383 //function : SetDegrees
384 //purpose : changes the degrees of the approximation.
385 //=======================================================================
387 void Approx_ComputeCLine::SetDegrees(const Standard_Integer degreemin,
388 const Standard_Integer degreemax)
390 mydegremin = degreemin;
391 mydegremax = degreemax;
394 //=======================================================================
395 //function : SetTolerances
396 //purpose : Changes the tolerances of the approximation.
397 //=======================================================================
399 void Approx_ComputeCLine::SetTolerances(const Standard_Real Tolerance3d,
400 const Standard_Real Tolerance2d)
402 mytol3d = Tolerance3d;
403 mytol2d = Tolerance2d;
406 //=======================================================================
407 //function : SetConstraints
408 //purpose : Changes the constraints of the approximation.
409 //=======================================================================
411 void Approx_ComputeCLine::SetConstraints(const AppParCurves_Constraint FirstC,
412 const AppParCurves_Constraint LastC)
418 //=======================================================================
419 //function : SetMaxSegments
420 //purpose : Changes the max number of segments, which is allowed for cutting.
421 //=======================================================================
423 void Approx_ComputeCLine::SetMaxSegments(const Standard_Integer theMaxSegments)
425 myMaxSegments = theMaxSegments;
428 //=======================================================================
429 //function : SetInvOrder
431 //=======================================================================
432 void Approx_ComputeCLine::SetInvOrder(const Standard_Boolean theInvOrder)
434 myInvOrder = theInvOrder;
437 //=======================================================================
438 //function : IsAllApproximated
439 //purpose : returns False if at a moment of the approximation,
440 // the status NoApproximation has been sent by the user
441 // when more points were needed.
442 //=======================================================================
444 Standard_Boolean Approx_ComputeCLine::IsAllApproximated()
449 //=======================================================================
450 //function : IsToleranceReached
451 //purpose : returns False if the status NoPointsAdded has been sent.
452 //=======================================================================
454 Standard_Boolean Approx_ComputeCLine::IsToleranceReached()
459 //=======================================================================
461 //purpose : returns the tolerances 2d and 3d of the <Index> MultiCurve.
462 //=======================================================================
464 void Approx_ComputeCLine::Error(const Standard_Integer Index,
465 Standard_Real& tol3d,
466 Standard_Real& tol2d) const
468 tol3d = Tolers3d.Value(Index);
469 tol2d = Tolers2d.Value(Index);