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