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. |
b311480e |
14 | |
7fd59977 |
15 | #include <StdFail_NotDone.hxx> |
16 | #include <Standard_DomainError.hxx> |
17 | #include <Standard_OutOfRange.hxx> |
18 | #include <Standard_ConstructionError.hxx> |
19 | #include <GCPnts_AbscissaType.hxx> |
20 | #include <TColStd_HArray1OfReal.hxx> |
21 | #include <TColStd_Array1OfReal.hxx> |
22 | #include <GeomAbs_CurveType.hxx> |
23 | #include <CPnts_AbscissaPoint.hxx> |
24 | #include <GCPnts_AbscissaPoint.hxx> |
25 | #include <Precision.hxx> |
26 | #include <gp_Circ.hxx> |
27 | #include <gp_Circ2d.hxx> |
28 | #include <gp_Vec.hxx> |
29 | #include <gp_Vec2d.hxx> |
30 | |
31 | |
37782ec2 |
32 | static Standard_Real GetParameterLengthRatio(const TheCurve& C) |
7fd59977 |
33 | { |
34 | switch (C.GetType()) { |
35 | |
36 | case GeomAbs_Circle : |
37 | return C.Circle().Radius(); |
38 | |
39 | case GeomAbs_Line : |
40 | return 1.; |
41 | |
42 | case GeomAbs_BezierCurve : |
43 | case GeomAbs_BSplineCurve : |
44 | { |
45 | if (!C.IsRational()) |
46 | return C.DN(0., 1).Magnitude(); |
47 | else |
48 | return RealLast(); |
49 | } |
50 | |
51 | default : |
52 | return RealLast(); |
53 | |
54 | } |
55 | } |
56 | |
57 | |
37782ec2 |
58 | static GCPnts_AbscissaType GetAbsType(const TheCurve& C) |
7fd59977 |
59 | { |
60 | if (C.NbIntervals(GeomAbs_C1) > 1) |
61 | return GCPnts_AbsComposite; |
62 | |
63 | switch (C.GetType()) { |
64 | |
65 | case GeomAbs_Line: |
66 | case GeomAbs_Circle: |
67 | return GCPnts_LengthParametrized; |
68 | case GeomAbs_BezierCurve: |
69 | { |
70 | Handle_TheBezierCurve BZ = C.Bezier(); |
71 | if (BZ->NbPoles() == 2 && !BZ->IsRational()) |
72 | return GCPnts_LengthParametrized; |
73 | else |
74 | return GCPnts_Parametrized; |
75 | } |
76 | case GeomAbs_BSplineCurve: |
77 | { |
78 | Handle_TheBSplineCurve BS = C.BSpline() ; |
79 | if (BS->NbPoles() == 2 && !BS->IsRational()) |
80 | return GCPnts_LengthParametrized; |
81 | else |
82 | return GCPnts_Parametrized; |
83 | } |
84 | default: |
85 | return GCPnts_Parametrized ; |
86 | } |
87 | } |
88 | |
89 | static Standard_Boolean Perform(Handle(TColStd_HArray1OfReal)& HParameters, |
37782ec2 |
90 | const TheCurve& C, |
7fd59977 |
91 | const Standard_Real Abscissa, |
92 | const Standard_Real U1, |
93 | const Standard_Real U2, |
94 | const Standard_Real TotalLength, |
95 | Standard_Integer &NbPoints, |
96 | const Standard_Real EPSILON) |
97 | { |
98 | Standard_Boolean NotDone = Standard_True; |
99 | Standard_Boolean LocalDone = Standard_True; |
100 | // Standard_Boolean Forward = Standard_True ; |
101 | Standard_Real UU1 = Min(U1, U2), UU2 = Max(U1, U2) ; |
102 | Standard_Integer Index ; |
103 | // Standard_Real UCurrent, Delta, Ui; |
104 | Standard_Real Delta, Ui; |
105 | NbPoints = 0 ; |
106 | |
107 | // |
108 | // this initialization avoids the computation of the Length |
109 | // of the curve |
110 | |
111 | Delta = (Abscissa/TotalLength) * (UU2 - UU1) ; |
112 | Index = 1 ; |
113 | HParameters->SetValue(Index,UU1) ; |
114 | while (NotDone) { |
115 | Ui = HParameters->Value(Index) + Delta; |
116 | if (Ui > UU2) { |
117 | // MSV 21.04.2004: OCC5739 (GCPnts_UniformAbscissa gives incorrect |
118 | // distribution of points) |
119 | // if (UU2 - HParameters->Value(Index) > 0.01*Delta) { |
120 | // Index += 1; |
121 | // } |
122 | // HParameters->SetValue(Index, UU2); |
123 | // NotDone = Standard_False; |
124 | // break; |
125 | Ui = UU2; |
126 | } |
127 | GCPnts_AbscissaPoint AbscissaFinder(C, |
128 | Abscissa, |
129 | HParameters->Value(Index), |
130 | Ui, |
131 | EPSILON) ; |
132 | if (AbscissaFinder.IsDone()) { |
133 | Index += 1 ; |
134 | Ui = AbscissaFinder.Parameter(); |
135 | if (Abs(Ui-UU2) <= EPSILON) { |
136 | HParameters->SetValue(Index, UU2); |
137 | NotDone = Standard_False; |
138 | } |
139 | else if (Ui < UU2) { |
140 | HParameters->SetValue(Index, Ui); |
141 | } |
142 | else { |
143 | HParameters->SetValue(Index, UU2); |
144 | NotDone = Standard_False; |
145 | } |
146 | NotDone = NotDone && (Index + 1 <= HParameters->Length()) ; |
147 | } |
148 | else { |
149 | |
150 | LocalDone = Standard_False ; |
151 | NotDone = Standard_True ; |
152 | Delta -= Delta/10; |
153 | if (Delta <= Precision::PConfusion()) break; |
154 | } |
155 | } |
156 | NbPoints = Index ; |
157 | return (LocalDone) ; |
158 | } |
159 | |
160 | |
161 | static Standard_Boolean |
162 | PerformLengthParametrized( Handle(TColStd_HArray1OfReal)& HParameters, |
37782ec2 |
163 | const TheCurve& C, |
7fd59977 |
164 | const Standard_Real Abscissa, |
165 | const Standard_Real U1, |
166 | const Standard_Real U2, |
167 | const Standard_Real TotalLength, |
168 | Standard_Integer &NbPoints, |
169 | const Standard_Real EPSILON) |
170 | { |
171 | Standard_Boolean NotDone = Standard_True; |
172 | // Standard_Boolean LocalDone = Standard_True; |
7fd59977 |
173 | Standard_Real UU1 = Min(U1, U2); |
174 | // Standard_Real UCurrent; |
175 | Standard_Real Delta, Ui; |
176 | Standard_Real UU2 = Max(U1, U2); |
7fd59977 |
177 | Standard_Integer Index ; |
178 | |
179 | // Ratio is defined as dl = Ratio * du |
180 | // for a circle of gp Ratio is equal to the radius of the circle. |
181 | // for a line of gp ratio is equal to 1.0 |
182 | Standard_Real Ratio = GetParameterLengthRatio(C); |
183 | |
184 | |
185 | if (Abscissa < 0.0e0) { |
7fd59977 |
186 | UU2 = Min(U1, U2); |
187 | UU1 = Max(U1, U2); |
188 | } |
189 | Delta = (Abscissa/TotalLength) * (UU2 - UU1) ; |
190 | Index = 1 ; |
191 | NbPoints = 0 ; |
192 | HParameters->SetValue(Index,UU1) ; |
193 | while (NotDone) { |
194 | Index += 1 ; |
195 | Ui = HParameters->Value(Index-1) + Delta; |
196 | if (Abs(Ui-UU2) <= EPSILON) { |
197 | HParameters->SetValue(Index, UU2); |
198 | NotDone = Standard_False; |
199 | } |
200 | else if (Ui < UU2) { |
201 | HParameters->SetValue(Index, Ui); |
202 | } |
203 | else { |
204 | NotDone = Standard_False; |
205 | if (Abs(HParameters->Value(Index-1) - UU2)*Ratio/Abscissa < 0.1) { |
206 | HParameters->SetValue(Index-1, UU2); |
207 | Index -= 1; |
208 | } |
209 | else |
210 | HParameters->SetValue(Index, UU2); |
211 | } |
212 | NotDone = (Index+1 <= HParameters->Length()) && NotDone ; |
213 | } |
214 | |
215 | NbPoints = Index ; |
216 | return Standard_True ; |
217 | } |
218 | |
219 | |
220 | //======================================================================= |
221 | //function : Initialize |
222 | //purpose : |
223 | //======================================================================= |
224 | |
37782ec2 |
225 | void GCPnts_UniformAbscissa::Initialize (const TheCurve& C, |
7fd59977 |
226 | const Standard_Real Abscissa, |
227 | const Standard_Real Tol) |
228 | { |
229 | Initialize(C, Abscissa, C.FirstParameter(), |
230 | C.LastParameter(), Tol); |
231 | } |
232 | |
233 | //======================================================================= |
234 | //function : GCPnts_UniformAbscissa |
235 | //purpose : |
236 | //======================================================================= |
237 | |
37782ec2 |
238 | GCPnts_UniformAbscissa::GCPnts_UniformAbscissa (const TheCurve& C, |
7fd59977 |
239 | const Standard_Real Abscissa, |
240 | const Standard_Real Tol) |
241 | { |
242 | Initialize(C, Abscissa, Tol); |
243 | } |
244 | |
245 | //======================================================================= |
246 | //function : GCPnts_UniformAbscissa |
247 | //purpose : |
248 | //======================================================================= |
249 | |
37782ec2 |
250 | GCPnts_UniformAbscissa::GCPnts_UniformAbscissa (const TheCurve& C, |
7fd59977 |
251 | const Standard_Real Abscissa, |
252 | const Standard_Real U1, |
253 | const Standard_Real U2, |
254 | const Standard_Real Tol) |
255 | { |
256 | Initialize(C, Abscissa, U1, U2, Tol); |
257 | } |
258 | |
259 | //======================================================================= |
260 | //function : GCPnts_UniformAbscissa |
261 | //purpose : |
262 | //======================================================================= |
263 | |
37782ec2 |
264 | GCPnts_UniformAbscissa::GCPnts_UniformAbscissa(const TheCurve& C, |
7fd59977 |
265 | const Standard_Integer NbPoints, |
266 | const Standard_Real Tol) |
267 | { |
268 | Initialize(C, NbPoints, Tol); |
269 | } |
270 | |
271 | //======================================================================= |
272 | //function : GCPnts_UniformAbscissa |
273 | //purpose : |
274 | //======================================================================= |
275 | |
37782ec2 |
276 | GCPnts_UniformAbscissa::GCPnts_UniformAbscissa(const TheCurve& C, |
7fd59977 |
277 | const Standard_Integer NbPoints, |
278 | const Standard_Real U1, |
279 | const Standard_Real U2, |
280 | const Standard_Real Tol) |
281 | { |
282 | Initialize(C, NbPoints, U1, U2, Tol); |
283 | } |
284 | |
285 | //======================================================================= |
286 | //function : Initialize |
287 | //purpose : |
288 | //======================================================================= |
289 | |
37782ec2 |
290 | void GCPnts_UniformAbscissa::Initialize(const TheCurve& C, |
7fd59977 |
291 | const Standard_Real Abscissa, |
292 | const Standard_Real U1, |
293 | const Standard_Real U2, |
294 | const Standard_Real Tol) |
295 | { |
296 | Standard_Real L ; |
297 | myAbscissa = Abscissa; |
298 | myNbPoints = 0 ; |
299 | myDone = Standard_False; |
300 | Standard_Real EPSILON; |
301 | |
302 | if(Tol < Precision::Confusion()) |
303 | EPSILON = C.Resolution(Precision::Confusion()); |
304 | else |
305 | EPSILON = C.Resolution(Tol); |
306 | |
307 | L = GCPnts_AbscissaPoint::Length(C, U1, U2, EPSILON); |
308 | if (L <= Precision::Confusion()) { |
309 | return; |
310 | } |
311 | Standard_Integer size ; |
312 | |
313 | // |
314 | // compute the total Length here so that we can |
315 | // guess the number of points instead of letting the |
316 | // constructor of CPnts_AbscissaPoint do that and loosing |
317 | // the information |
318 | // |
319 | // |
320 | |
321 | // modified by Igor Motchalov 23/04/2001 |
322 | // size = (Standard_Integer )( (L/Abs(Abscissa)) + 5 ); |
323 | Standard_Real sizeR=L/Abs(Abscissa) + 5; |
324 | if (sizeR < IntegerLast()) { |
325 | size=(Standard_Integer) sizeR; |
326 | } else { |
327 | return; |
328 | } |
329 | |
330 | if (!myParams.IsNull()) { |
331 | if (myParams->Length() < size) { |
332 | myParams.Nullify() ; |
333 | myParams = new |
334 | TColStd_HArray1OfReal(1,size) ; |
335 | } |
336 | } |
337 | else { |
338 | myParams = new |
339 | TColStd_HArray1OfReal(1,size) ; |
340 | } |
341 | |
342 | // Standard_Real EPSILON = C.Resolution(Precision::Confusion()); |
343 | GCPnts_AbscissaType Type = GetAbsType(C); |
344 | switch (Type) { |
345 | case GCPnts_LengthParametrized : |
346 | myDone = PerformLengthParametrized(myParams, |
347 | C, |
348 | Abscissa, |
349 | U1, |
350 | U2, |
351 | L, |
352 | myNbPoints, |
353 | EPSILON); |
354 | break; |
355 | case GCPnts_Parametrized: |
356 | case GCPnts_AbsComposite: |
357 | myDone = Perform(myParams, |
358 | C, |
359 | Abscissa, |
360 | U1, |
361 | U2, |
362 | L, |
363 | myNbPoints, |
364 | EPSILON); |
365 | break; |
366 | } |
367 | } |
368 | |
369 | |
370 | //======================================================================= |
371 | //function : Initialize |
372 | //purpose : |
373 | //======================================================================= |
374 | |
37782ec2 |
375 | void GCPnts_UniformAbscissa::Initialize(const TheCurve& C, |
7fd59977 |
376 | const Standard_Integer NbPoints, |
377 | const Standard_Real Tol) |
378 | { |
379 | Initialize(C, NbPoints, C.FirstParameter(), |
380 | C.LastParameter(), Tol); |
381 | } |
382 | |
383 | |
384 | //======================================================================= |
385 | //function : Initialize |
386 | //purpose : |
387 | //======================================================================= |
388 | |
37782ec2 |
389 | void GCPnts_UniformAbscissa::Initialize(const TheCurve& C, |
7fd59977 |
390 | const Standard_Integer NbPoints, |
391 | const Standard_Real U1, |
392 | const Standard_Real U2, |
393 | const Standard_Real Tol) |
394 | { |
395 | Standard_ConstructionError_Raise_if(NbPoints <= 1, ""); |
396 | Standard_Real Abscissa ; |
397 | myNbPoints = 0 ; |
398 | myDone = Standard_False; |
399 | Standard_Real EPSILON; |
400 | |
401 | if(Tol < Precision::Confusion()) |
402 | EPSILON = C.Resolution(Precision::Confusion()); |
403 | else |
404 | EPSILON = C.Resolution(Tol); |
405 | |
406 | // |
407 | // although very similar to Initialize with Abscissa this avoid |
408 | // the computation of the total length of the curve twice |
409 | // |
410 | Standard_Real L = GCPnts_AbscissaPoint::Length(C, U1, U2, EPSILON) ; |
411 | |
412 | if (L <= Precision::Confusion()) { |
413 | return; |
414 | } |
415 | |
416 | Abscissa = |
417 | myAbscissa = L / (NbPoints - 1); |
418 | |
419 | Standard_Integer size ; |
420 | |
421 | // |
422 | // compute the total Length here so that we can |
423 | // guess the number of points instead of letting the |
424 | // constructor of CPnts_AbscissaPoint do that and loosing |
425 | // the information |
426 | // |
427 | // |
428 | |
429 | size = NbPoints + 5 ; |
430 | |
431 | |
432 | if (!myParams.IsNull()) { |
433 | if (myParams->Length() < size) { |
434 | myParams.Nullify() ; |
435 | myParams = new |
436 | TColStd_HArray1OfReal(1,size) ; |
437 | } |
438 | } |
439 | else { |
440 | myParams = new |
441 | TColStd_HArray1OfReal(1,size) ; |
442 | } |
443 | |
444 | |
445 | myNbPoints = 0 ; |
446 | GCPnts_AbscissaType Type = GetAbsType(C); |
447 | switch (Type) { |
448 | case GCPnts_LengthParametrized: |
449 | myDone = PerformLengthParametrized(myParams, |
450 | C, |
451 | Abscissa, |
452 | U1, |
453 | U2, |
454 | L, |
455 | myNbPoints, |
456 | EPSILON); |
457 | break; |
458 | case GCPnts_Parametrized: |
459 | case GCPnts_AbsComposite: |
460 | myDone = Perform(myParams, |
461 | C, |
462 | Abscissa, |
463 | U1, |
464 | U2, |
465 | L, |
466 | myNbPoints, |
467 | EPSILON); |
468 | break; |
469 | } |
470 | } |
471 | |
472 | |
473 | |
474 | |
475 | |
476 | |