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 |
28 | const 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 | |
38 | Approx_ComputeCLine::Approx_ComputeCLine |
afb3647b |
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) |
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 | |
66 | Approx_ComputeCLine::Approx_ComputeCLine |
afb3647b |
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) |
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 | |
92 | void 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 | |
222 | Standard_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 | |
232 | AppParCurves_MultiCurve Approx_ComputeCLine::Value(const Standard_Integer Index) |
233 | const |
234 | { |
235 | return myMultiCurves.Value(Index); |
236 | } |
237 | |
238 | //======================================================================= |
239 | //function : Compute |
240 | //purpose : is internally used by the algorithms. |
241 | //======================================================================= |
242 | |
243 | Standard_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 | |
372 | void 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 | |
385 | void 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 | |
397 | void 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 | |
409 | void 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 |
421 | void Approx_ComputeCLine::SetMaxSegments(const Standard_Integer theMaxSegments) |
f998596a |
422 | { |
423 | myMaxSegments = theMaxSegments; |
424 | } |
425 | |
ba7f665d |
426 | //======================================================================= |
427 | //function : SetInvOrder |
428 | //purpose : |
429 | //======================================================================= |
430 | void 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 | |
442 | Standard_Boolean Approx_ComputeCLine::IsAllApproximated() |
443 | const { |
444 | return alldone; |
445 | } |
446 | |
447 | //======================================================================= |
448 | //function : IsToleranceReached |
449 | //purpose : returns False if the status NoPointsAdded has been sent. |
450 | //======================================================================= |
451 | |
452 | Standard_Boolean Approx_ComputeCLine::IsToleranceReached() |
453 | const { |
454 | return tolreached; |
455 | } |
456 | |
457 | //======================================================================= |
458 | //function : Error |
459 | //purpose : returns the tolerances 2d and 3d of the <Index> MultiCurve. |
460 | //======================================================================= |
461 | |
462 | void 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 | } |