7fd59977 |
1 | // pdn 04.12.98 Add method using Adaptor_Curve |
2 | //:j8 abv 10.12.98 TR10 r0501_db.stp #9423 |
3 | //pdn 25.12.98 private method ProjectAct |
4 | //szv#4 S4163 |
5 | //:s5 abv 22.04.99 Adding debug printouts in catch {} blocks |
6 | // abv 14.05.99 S4174: Adding method for exact computing of the boundary box |
7 | // gka 21.06.99 S4208: adding method NextProject(Adaptor_Curve) |
8 | // msv 30.05.00 correct IsPlanar for a conic curve |
9 | #include <ShapeAnalysis_Curve.ixx> |
10 | |
11 | #include <ElCLib.hxx> |
12 | |
13 | #include <Geom2d_BoundedCurve.hxx> |
14 | #include <Geom2d_Line.hxx> |
15 | #include <Geom_BSplineCurve.hxx> |
16 | #include <GeomAdaptor_Curve.hxx> |
17 | |
18 | #include <Precision.hxx> |
19 | |
20 | #include <Standard_ErrorHandler.hxx> |
21 | #include <Standard_Failure.hxx> |
22 | #include <Adaptor3d_Curve.hxx> |
23 | #include <Extrema_ExtPC.hxx> |
24 | #include <ShapeAnalysis.hxx> |
25 | #include <TColgp_SequenceOfPnt.hxx> |
26 | #include <Geom_Line.hxx> |
27 | #include <Geom_Conic.hxx> |
28 | #include <Geom_TrimmedCurve.hxx> |
29 | #include <Geom_OffsetCurve.hxx> |
30 | #include <Geom_BezierCurve.hxx> |
31 | #include <ShapeExtend_ComplexCurve.hxx> |
32 | #include <Geom2d_Conic.hxx> |
33 | #include <Geom2d_TrimmedCurve.hxx> |
34 | #include <Geom2d_BSplineCurve.hxx> |
35 | #include <Geom2d_BezierCurve.hxx> |
36 | |
37 | #include <Geom2d_OffsetCurve.hxx> |
38 | #include <Geom2dInt_Geom2dCurveTool.hxx> |
39 | #include <Geom2dAdaptor_Curve.hxx> |
40 | #include <Geom_Circle.hxx> |
41 | |
42 | |
43 | //======================================================================= |
44 | //function : ProjectOnSegments |
45 | //purpose : |
46 | //======================================================================= |
47 | |
48 | static void ProjectOnSegments (const Adaptor3d_Curve& AC, const gp_Pnt& P3D, |
49 | const Standard_Integer nbseg, |
50 | Standard_Real& uMin, Standard_Real& uMax, |
51 | Standard_Real& distmin, gp_Pnt& proj, Standard_Real& param) |
52 | { |
53 | // On considere <nbseg> points sur [uMin,uMax] |
54 | // Quel est le plus proche. Et quel est le nouvel intervalle |
55 | // (il ne peut pas deborder l ancien) |
56 | Standard_Real u, dist, delta = (nbseg == 0)? 0 : (uMax-uMin)/nbseg; //szv#4:S4163:12Mar99 anti-exception |
57 | for (Standard_Integer i = 0; i <= nbseg; i ++) { |
58 | u = uMin + (delta * i); |
59 | gp_Pnt PU = AC.Value (u); |
60 | dist = PU.Distance (P3D); |
61 | if (dist < distmin) { distmin = dist; proj = PU; param = u; } |
62 | } |
63 | |
64 | #ifdef DEBUG |
65 | cout<<"ShapeAnalysis_Geom:Project, param="<<param<<" -> distmin="<<distmin<<endl; |
66 | #endif |
67 | |
68 | uMax = Min (uMax, param+delta); |
69 | uMin = Max (uMin, param-delta); |
70 | } |
71 | |
72 | |
73 | //======================================================================= |
74 | //function : CurveNewton |
75 | //purpose : Newton algo on curve (study S4030) |
76 | //======================================================================= |
77 | |
78 | static Standard_Boolean CurveNewton(const Standard_Real paramPrev, |
79 | const Adaptor3d_Curve& Ad, |
80 | const gp_Pnt& P3D, |
81 | const Standard_Real /*preci*/, |
82 | Standard_Real& param, |
83 | const Standard_Real cf, |
84 | const Standard_Real cl) |
85 | { |
86 | //szv#4:S4163:12Mar99 optimized |
87 | Standard_Real uMin = cf, uMax = cl; |
88 | |
89 | Standard_Real Tol = Precision::Confusion(); |
90 | Standard_Real Tol2 = Tol*Tol, rs2p = 1.e+10; |
91 | Standard_Real X = paramPrev; |
92 | |
93 | for ( Standard_Integer i=0; i<20; i++) { |
94 | gp_Vec v1, v2; |
95 | gp_Pnt pnt; |
96 | Ad.D2 (X, pnt, v1, v2); |
97 | Standard_Real nv1 = v1.SquareMagnitude(); |
98 | if (nv1 < 1e-10) break; |
99 | |
100 | gp_Vec rs (P3D, pnt); |
101 | Standard_Real D = nv1 + (rs * v2); |
102 | if ( fabs( D ) <1e-10) break; |
103 | |
104 | Standard_Real dX = -(rs *v1)/D; |
105 | X += dX; |
106 | |
107 | Standard_Real rs2 = rs.SquareMagnitude(); |
108 | if (rs2 > 4.*rs2p) break; |
109 | rs2p = rs2; |
110 | |
111 | if ( fabs(dX) > 1e-12) continue; |
112 | |
113 | if (X < uMin || X > uMax) break; |
114 | |
115 | Standard_Real rsn = rs * v1; |
116 | if (rsn*rsn/nv1 > Tol2) break; |
117 | param = X; |
118 | return Standard_True; |
119 | } |
120 | |
121 | // cout <<"NewtonC: failed after " << i+1 << " iterations (fail " << fail << " )" << endl; |
122 | return Standard_False; |
123 | } |
124 | |
125 | //======================================================================= |
126 | //function : Project |
127 | //purpose : |
128 | //======================================================================= |
129 | |
130 | Standard_Real ShapeAnalysis_Curve::Project(const Handle(Geom_Curve)& C3D, |
131 | const gp_Pnt& P3D, |
132 | const Standard_Real preci, |
133 | gp_Pnt& proj, |
134 | Standard_Real& param, |
135 | const Standard_Boolean AdjustToEnds) const |
136 | { |
137 | Standard_Real uMin = C3D->FirstParameter(); |
138 | Standard_Real uMax = C3D->LastParameter(); |
139 | if (uMin < uMax) return Project (C3D,P3D,preci,proj,param,uMin,uMax,AdjustToEnds); |
140 | else return Project (C3D,P3D,preci,proj,param,uMax,uMin,AdjustToEnds); |
141 | } |
142 | |
143 | //======================================================================= |
144 | //function : Project |
145 | //purpose : |
146 | //======================================================================= |
147 | |
148 | Standard_Real ShapeAnalysis_Curve::Project(const Handle(Geom_Curve)& C3D, |
149 | const gp_Pnt& P3D, |
150 | const Standard_Real preci, |
151 | gp_Pnt& proj, |
152 | Standard_Real& param, |
153 | const Standard_Real cf, |
154 | const Standard_Real cl, |
155 | const Standard_Boolean AdjustToEnds) const |
156 | { |
157 | Standard_Real distmin; |
158 | Standard_Real uMin = (cf < cl ? cf : cl); |
159 | Standard_Real uMax = (cf < cl ? cl : cf); |
160 | |
161 | if (C3D->IsKind(STANDARD_TYPE(Geom_BoundedCurve))) { |
162 | Standard_Real prec = ( AdjustToEnds ? preci : Precision::Confusion() ); //:j8 abv 10 Dec 98: tr10_r0501_db.stp #9423: protection against densing of points near one end |
163 | gp_Pnt LowBound = C3D->Value(uMin); |
164 | gp_Pnt HigBound = C3D->Value(uMax); |
165 | distmin = LowBound.Distance(P3D); |
166 | if (distmin <= prec) { |
167 | param = uMin; |
168 | proj = LowBound; |
169 | return distmin; |
170 | } |
171 | distmin = HigBound.Distance(P3D); |
172 | if (distmin <= prec) { |
173 | param = uMax; |
174 | proj = HigBound; |
175 | return distmin; |
176 | } |
177 | } |
178 | |
179 | GeomAdaptor_Curve GAC(C3D, uMin, uMax); |
180 | if (!C3D->IsClosed()) { |
181 | //modified by rln on 16/12/97 after CSR# PRO11641 entity 20767 |
182 | //the VIso was not closed (according to C3D->IsClosed()) while it "almost" |
183 | //was (the distance between ends of the curve was a little bit more than |
184 | //Precision::Confusion()) |
185 | //in that case value 0.1 was too much and this method returned not correct parameter |
186 | //uMin = uMin - 0.1; |
187 | //uMax = uMax + 0.1; |
188 | // modified by pdn on 01.07.98 after BUC60195 entity 1952 (Min() added) |
189 | Standard_Real delta = Min (GAC.Resolution (preci), (uMax - uMin) * 0.1); |
190 | uMin -= delta; |
191 | uMax += delta; |
192 | GAC.Load(C3D, uMin, uMax); |
193 | } |
194 | |
195 | return ProjectAct(GAC, P3D, preci, proj, param); |
196 | } |
197 | |
198 | //======================================================================= |
199 | //function : Project |
200 | //purpose : |
201 | //======================================================================= |
202 | |
203 | Standard_Real ShapeAnalysis_Curve::Project(const Adaptor3d_Curve& C3D, |
204 | const gp_Pnt& P3D, |
205 | const Standard_Real preci, |
206 | gp_Pnt& proj, |
207 | Standard_Real& param, |
208 | const Standard_Boolean AdjustToEnds) const |
209 | |
210 | { |
211 | Standard_Real uMin = C3D.FirstParameter(); |
212 | Standard_Real uMax = C3D.LastParameter(); |
213 | Standard_Real distmin; |
214 | if (!Precision::IsInfinite(uMin)||!Precision::IsInfinite(uMax)) { |
215 | Standard_Real prec = ( AdjustToEnds ? preci : Precision::Confusion() ); //:j8 abv 10 Dec 98: tr10_r0501_db.stp #9423: protection against densing of points near one end |
216 | gp_Pnt LowBound = C3D.Value(uMin); |
217 | gp_Pnt HigBound = C3D.Value(uMax); |
218 | distmin = LowBound.Distance(P3D); |
219 | if (distmin <= prec) { |
220 | param = uMin; |
221 | proj = LowBound; |
222 | return distmin; |
223 | } |
224 | distmin = HigBound.Distance(P3D); |
225 | if (distmin <= prec) { |
226 | param = uMax; |
227 | proj = HigBound; |
228 | return distmin; |
229 | } |
230 | } |
231 | return ProjectAct(C3D, P3D, preci, proj, param); |
232 | } |
233 | |
234 | //======================================================================= |
235 | //function : ProjectAct |
236 | //purpose : |
237 | //======================================================================= |
238 | |
239 | Standard_Real ShapeAnalysis_Curve::ProjectAct(const Adaptor3d_Curve& C3D, |
240 | const gp_Pnt& P3D, |
241 | const Standard_Real preci, |
242 | gp_Pnt& proj, |
243 | Standard_Real& param) const |
244 | |
245 | { |
246 | Standard_Boolean useExtrema = Standard_True; //:i5 |
247 | |
248 | #ifdef WNT |
249 | //:i5 abv 11 Sep 98: UKI60195.igs on NT: hanging on null-length bsplines |
250 | if (C3D.IsClosed() && C3D.GetType()==GeomAbs_BSplineCurve) { |
251 | Handle(Geom_BSplineCurve) bspl = C3D.BSpline(); |
252 | Standard_Real prec2 = gp::Resolution(); |
253 | prec2 *= prec2; |
254 | gp_Pnt p0 = bspl->Pole(1), p1; |
255 | for ( Standard_Integer i=2; i <= bspl->NbPoles(); i++, p0 = p1 ) { |
256 | p1 = bspl->Pole(i); |
257 | if ( p0.SquareDistance ( p1 ) <= prec2 ) { |
258 | useExtrema = Standard_False; |
259 | break; |
260 | } |
261 | } |
262 | } |
263 | #endif |
264 | |
265 | Standard_Boolean OK = Standard_False; |
266 | if ( useExtrema ) { //:i5 //szv#4:S4163:12Mar99 try moved into if |
267 | try { |
268 | OCC_CATCH_SIGNALS |
269 | Extrema_ExtPC myExtPC(P3D,C3D); |
270 | //Standard_Boolean done = myExtPC.IsDone() && ( myExtPC.NbExt() > 0); //szv#4:S4163:12Mar99 not needed |
271 | if ( myExtPC.IsDone() && ( myExtPC.NbExt() > 0) ) { |
272 | Standard_Real dist2, dist2Min = myExtPC.SquareDistance(1); |
273 | Standard_Integer index = 1; |
274 | for ( Standard_Integer i = 2; i <= myExtPC.NbExt(); i++) { |
275 | dist2 = myExtPC.SquareDistance(i); |
276 | if ( dist2 < dist2Min) { dist2Min = dist2; index = i; } |
277 | } |
278 | param = (myExtPC.Point(index)).Parameter(); |
279 | proj = (myExtPC.Point(index)).Value(); |
280 | OK = Standard_True; |
281 | } |
282 | } |
283 | catch(Standard_Failure) { |
284 | OK = Standard_False; |
285 | #ifdef DEB //:s5 |
286 | cout << "\nWarning: ShapeAnalysis_Curve::ProjectAct(): Exception in Extrema_ExtPC: "; |
287 | Standard_Failure::Caught()->Print(cout); cout << endl; |
288 | #endif |
289 | } |
290 | } |
291 | |
292 | //szv#4:S4163:12Mar99 moved |
293 | Standard_Real uMin = C3D.FirstParameter(), uMax = C3D.LastParameter(); |
294 | Standard_Boolean closed = Standard_False; // si on franchit les bornes ... |
295 | Standard_Real distmin = RealLast(), valclosed = 0.; |
296 | Standard_Real aModParam = param; |
297 | Standard_Real aModMin = distmin; |
298 | |
299 | // PTV 29.05.2002 remember the old solution, cause it could be better |
300 | Standard_Real anOldParam =0.; |
301 | Standard_Boolean IsHaveOldSol = Standard_False; |
302 | gp_Pnt anOldProj; |
303 | if (OK) { |
304 | IsHaveOldSol = Standard_True; |
305 | anOldProj = proj; |
306 | anOldParam = param; |
307 | distmin = proj.Distance (P3D); |
308 | aModMin = distmin; |
309 | if (distmin > preci) OK = Standard_False; |
310 | // Cas TrimmedCurve a cheval. Voir la courbe de base. |
311 | // Si fermee, passer une periode |
312 | if (C3D.IsClosed()) { |
313 | closed = Standard_True; |
314 | valclosed = uMax - uMin; //szv#4:S4163:12Mar99 optimized |
315 | } |
316 | } |
317 | |
318 | if (!OK) { |
319 | // BUG NICOLAS - Si le point est sur la courbe 0 Solutions |
320 | // Cela fonctionne avec ElCLib |
321 | |
322 | // D une facon generale, on essaie de TOUJOURS retourner un resultat |
323 | // MEME PAS BIEN BON. L appelant pourra decider alors quoi faire |
324 | param = 0.; |
325 | |
326 | switch(C3D.GetType()) { |
327 | case GeomAbs_Circle: |
328 | { |
329 | const gp_Circ& aCirc = C3D.Circle(); |
330 | proj = aCirc.Position().Location(); |
331 | if(aCirc.Radius() <= gp::Resolution() || |
332 | P3D.SquareDistance(proj) <= gp::Resolution() ) { |
333 | param = C3D.FirstParameter(); |
334 | proj = proj.XYZ() + aCirc.XAxis().Direction().XYZ() * aCirc.Radius(); |
335 | } |
336 | else { |
337 | param = ElCLib::Parameter(aCirc, P3D); |
338 | proj = ElCLib::Value(param, aCirc); |
339 | } |
340 | closed = Standard_True; |
341 | valclosed = 2.*PI; |
342 | } |
343 | break; |
344 | case GeomAbs_Hyperbola: |
345 | { |
346 | param = ElCLib::Parameter(C3D.Hyperbola(), P3D); |
347 | proj = ElCLib::Value(param, C3D.Hyperbola()); |
348 | } |
349 | break; |
350 | case GeomAbs_Parabola: |
351 | { |
352 | param = ElCLib::Parameter(C3D.Parabola(), P3D); |
353 | proj = ElCLib::Value(param, C3D.Parabola()); |
354 | } |
355 | break; |
356 | case GeomAbs_Line: |
357 | { |
358 | param = ElCLib::Parameter(C3D.Line(), P3D); |
359 | proj = ElCLib::Value(param, C3D.Line()); |
360 | } |
361 | break; |
362 | case GeomAbs_Ellipse: |
363 | { |
364 | param = ElCLib::Parameter(C3D.Ellipse(), P3D); |
365 | proj = ElCLib::Value(param, C3D.Ellipse()); |
366 | closed = Standard_True; |
367 | valclosed = 2.*PI; |
368 | |
369 | } |
370 | break; |
371 | default: |
372 | { |
373 | // on ne va quand meme pas se laisser abattre ... ??? |
374 | // on tente ceci : 21 points sur la courbe, quel est le plus proche |
375 | distmin = Precision::Infinite(); |
376 | ProjectOnSegments (C3D,P3D,25,uMin,uMax,distmin,proj,param); |
377 | if (distmin <= preci) return distmin; |
378 | if (CurveNewton(param, C3D, P3D, preci, param, uMin, uMax)) { //:S4030 |
379 | C3D.D0(param, proj); |
380 | Standard_Real aDistNewton = P3D.Distance(proj); |
381 | if(aDistNewton < aModMin) |
382 | return aDistNewton; |
383 | } |
384 | // cout <<"newton failed"<<endl; |
385 | ProjectOnSegments (C3D,P3D,40,uMin,uMax,distmin,proj,param); |
386 | if (distmin <= preci) return distmin; |
387 | ProjectOnSegments (C3D,P3D,20,uMin,uMax,distmin,proj,param); |
388 | if (distmin <= preci) return distmin; |
389 | ProjectOnSegments (C3D,P3D,25,uMin,uMax,distmin,proj,param); |
390 | if (distmin <= preci) return distmin; |
391 | ProjectOnSegments (C3D,P3D,40,uMin,uMax,distmin,proj,param); |
392 | if (distmin <= preci) return distmin; |
393 | // soyons raisonnable ... |
394 | if(distmin > aModMin) { |
395 | distmin = aModMin; |
396 | param = aModParam; |
397 | } |
398 | |
399 | return distmin; |
400 | } |
401 | } |
402 | } |
403 | |
404 | // p = PPOC.LowerDistanceParameter(); cf try |
405 | if ( closed && ( param < uMin || param > uMax ) ) |
406 | param += ShapeAnalysis::AdjustByPeriod ( param, 0.5 * ( uMin + uMax ), valclosed ); |
407 | |
408 | if (IsHaveOldSol) { |
409 | // PTV 29.05.2002 Compare old solution and new; |
410 | Standard_Real adist1, adist2; |
411 | adist1 = anOldProj.SquareDistance(P3D); |
412 | adist2 = proj.SquareDistance (P3D); |
413 | if (adist1 < adist2) { |
414 | proj = anOldProj; |
415 | param = anOldParam; |
416 | } |
417 | } |
418 | return proj.Distance (P3D); |
419 | } |
420 | |
421 | |
422 | //======================================================================= |
423 | //function : NextProject |
424 | //purpose : Newton algo for projecting point on curve (S4030) |
425 | //======================================================================= |
426 | |
427 | Standard_Real ShapeAnalysis_Curve::NextProject(const Standard_Real paramPrev, |
428 | const Handle(Geom_Curve)& C3D, |
429 | const gp_Pnt& P3D, |
430 | const Standard_Real preci, |
431 | gp_Pnt& proj, |
432 | Standard_Real& param, |
433 | const Standard_Real cf, |
434 | const Standard_Real cl, |
435 | const Standard_Boolean AdjustToEnds) const |
436 | { |
437 | Standard_Real uMin = (cf < cl ? cf : cl); |
438 | Standard_Real uMax = (cf < cl ? cl : cf); |
439 | Standard_Real distmin; |
440 | if (C3D->IsKind(STANDARD_TYPE(Geom_BoundedCurve))) { |
441 | Standard_Real prec = ( AdjustToEnds ? preci : Precision::Confusion() ); //:j8 abv 10 Dec 98: tr10_r0501_db.stp #9423: protection against densing of points near one end |
442 | gp_Pnt LowBound = C3D->Value(uMin); |
443 | gp_Pnt HigBound = C3D->Value(uMax); |
444 | distmin = LowBound.Distance(P3D); |
445 | if (distmin <= prec) { |
446 | param = uMin; |
447 | proj = LowBound; |
448 | return distmin; |
449 | } |
450 | distmin = HigBound.Distance(P3D); |
451 | if (distmin <= prec) { |
452 | param = uMax; |
453 | proj = HigBound; |
454 | return distmin; |
455 | } |
456 | } |
457 | |
458 | GeomAdaptor_Curve GAC(C3D, uMin, uMax); |
459 | if (!C3D->IsClosed()) { |
460 | //modified by rln on 16/12/97 after CSR# PRO11641 entity 20767 |
461 | //the VIso was not closed (according to C3D->IsClosed()) while it "almost" |
462 | //was (the distance between ends of the curve was a little bit more than |
463 | //Precision::Confusion()) |
464 | //in that case value 0.1 was too much and this method returned not correct parameter |
465 | //uMin = uMin - 0.1; |
466 | //uMax = uMax + 0.1; |
467 | // modified by pdn on 01.07.98 after BUC60195 entity 1952 (Min() added) |
468 | Standard_Real delta = Min (GAC.Resolution (preci), (uMax - uMin) * 0.1); |
469 | uMin -= delta; |
470 | uMax += delta; |
471 | GAC.Load(C3D, uMin, uMax); |
472 | } |
473 | return NextProject ( paramPrev, GAC, P3D, preci, proj, param ); |
474 | } |
475 | |
476 | //======================================================================= |
477 | //function : NextProject |
478 | //purpose : |
479 | //======================================================================= |
480 | |
481 | Standard_Real ShapeAnalysis_Curve::NextProject(const Standard_Real paramPrev, |
482 | const Adaptor3d_Curve& C3D, |
483 | const gp_Pnt& P3D, |
484 | const Standard_Real preci, |
485 | gp_Pnt& proj, |
486 | Standard_Real& param) const |
487 | { |
488 | Standard_Real uMin = C3D.FirstParameter(); |
489 | Standard_Real uMax = C3D.LastParameter(); |
490 | |
491 | if (CurveNewton(paramPrev, C3D, P3D, preci, param, uMin, uMax)) { |
492 | C3D.D0(param, proj); |
493 | return P3D.Distance(proj); |
494 | } |
495 | |
496 | return Project(C3D, P3D, preci, proj, param); |
497 | } |
498 | |
499 | //======================================================================= |
500 | //function : AdjustParameters |
501 | //purpose : Copied from StepToTopoDS_GeometricTuul::UpdateParam3d (Aug 2001) |
502 | //======================================================================= |
503 | |
504 | Standard_Boolean ShapeAnalysis_Curve::ValidateRange (const Handle(Geom_Curve)& theCurve, |
505 | Standard_Real& First, Standard_Real& Last, |
506 | const Standard_Real preci) const |
507 | { |
508 | // First et/ou Last peuvent etre en dehors des bornes naturelles de la courbe. |
509 | // On donnera alors la valeur en bout a First et/ou Last |
510 | |
511 | Standard_Real cf = theCurve->FirstParameter(); |
512 | Standard_Real cl = theCurve->LastParameter(); |
513 | // Standard_Real preci = BRepAPI::Precision(); |
514 | |
515 | if (theCurve->IsKind(STANDARD_TYPE(Geom_BoundedCurve)) && !theCurve->IsClosed()) { |
516 | if (First < cf) { |
517 | #ifdef DEBUG |
518 | cout << "Update Edge First Parameter to Curve First Parameter" << endl; |
519 | #endif |
520 | First = cf; |
521 | } |
522 | else if (First > cl) { |
523 | #ifdef DEBUG |
524 | cout << "Update Edge First Parameter to Curve Last Parameter" << endl; |
525 | #endif |
526 | First = cl; |
527 | } |
528 | if (Last < cf) { |
529 | #ifdef DEBUG |
530 | cout << "Update Edge Last Parameter to Curve First Parameter" << endl; |
531 | #endif |
532 | Last = cf; |
533 | } |
534 | else if (Last > cl) { |
535 | #ifdef DEBUG |
536 | cout << "Update Edge Last Parameter to Curve Last Parameter" << endl; |
537 | #endif |
538 | Last = cl; |
539 | } |
540 | } |
541 | |
542 | if (First < Last) return Standard_True; |
543 | |
544 | // 15.11.2002 PTV OCC966 |
545 | if (ShapeAnalysis_Curve::IsPeriodic(theCurve)) |
546 | ElCLib::AdjustPeriodic(cf,cl,Precision::PConfusion(),First,Last); //:a7 abv 11 Feb 98: preci -> PConfusion() |
547 | else if (theCurve->IsClosed()) { |
548 | // l'un des points projecte se trouve sur l'origine du parametrage |
549 | // de la courbe 3D. L algo a donne cl +- preci au lieu de cf ou vice-versa |
550 | // DANGER precision 3d applique a une espace 1d |
551 | |
552 | // Last = cf au lieu de Last = cl |
553 | if (Abs(Last - cf) < Precision::PConfusion() /*preci*/) Last = cl ; |
554 | // First = cl au lieu de First = cf |
555 | else if (Abs(First - cl) < Precision::PConfusion() /*preci*/) First = cf; |
556 | |
557 | // on se trouve dans un cas ou l origine est traversee |
558 | // illegal sur une courbe fermee non periodique |
559 | // on inverse quand meme les parametres !!!!!! |
560 | else { |
561 | //:S4136 abv 20 Apr 99: r0701_ug.stp #6230: add check in 3d |
562 | if ( theCurve->Value(First).Distance(theCurve->Value(cf)) < preci ) First = cf; |
563 | if ( theCurve->Value(Last).Distance(theCurve->Value(cl)) < preci ) Last = cl; |
564 | if ( First > Last ) { |
565 | #ifdef DEBUG |
566 | cout << "Warning : parameter range of edge crossing non periodic curve origin" << endl; |
567 | #endif |
568 | Standard_Real tmp = First; |
569 | First = Last; |
570 | Last = tmp; |
571 | } |
572 | } |
573 | } |
574 | // The curve is closed within the 3D tolerance |
575 | else if (theCurve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) { |
576 | Handle(Geom_BSplineCurve) aBSpline = |
577 | Handle(Geom_BSplineCurve)::DownCast(theCurve); |
578 | if (aBSpline->StartPoint().Distance(aBSpline->EndPoint()) <= preci ) { |
579 | //:S4136 <= BRepAPI::Precision()) { |
580 | // l'un des points projecte se trouve sur l'origine du parametrage |
581 | // de la courbe 3D. L algo a donne cl +- preci au lieu de cf ou vice-versa |
582 | // DANGER precision 3d applique a une espace 1d |
583 | |
584 | // Last = cf au lieu de Last = cl |
585 | if (Abs(Last - cf) < Precision::PConfusion() /*preci*/) Last = cl ; |
586 | // First = cl au lieu de First = cf |
587 | else if (Abs(First - cl) < Precision::PConfusion() /*preci*/) First = cf; |
588 | |
589 | // on se trouve dans un cas ou l origine est traversee |
590 | // illegal sur une courbe fermee non periodique |
591 | // on inverse quand meme les parametres !!!!!! |
592 | else { |
593 | #ifdef DEBUG |
594 | cout << "Warning : parameter range of edge crossing non periodic curve origin" << endl; |
595 | #endif |
596 | Standard_Real tmp = First; |
597 | First = Last; |
598 | Last = tmp; |
599 | } |
600 | } |
601 | //abv 15.03.00 #72 bm1_pe_t4 protection of exceptions in draw |
602 | else if ( First > Last ) { |
603 | #ifdef DEBUG |
604 | cout << "Warning: parameter range is bad; curve reversed" << endl; |
605 | #endif |
606 | First = theCurve->ReversedParameter ( First ); |
607 | Last = theCurve->ReversedParameter ( Last ); |
608 | theCurve->Reverse(); |
609 | } |
610 | //:j9 abv 11 Dec 98: PRO7747 #4875, after :j8: else |
611 | if (First == Last) { //gka 10.07.1998 file PRO7656 entity 33334 |
612 | First = cf; Last = cl; |
613 | return Standard_False; |
614 | } |
615 | } |
616 | else { |
617 | #ifdef DEBUG |
618 | cout << "UpdateParam3d Failed" << endl; |
619 | cout << " - Curve Type : " << theCurve->DynamicType() << endl; |
620 | cout << " - Param 1 : " << First << endl; |
621 | cout << " - Param 2 : " << Last << endl; |
622 | #endif |
623 | //abv 15.03.00 #72 bm1_pe_t4 protection of exceptions in draw |
624 | if ( First > Last ) { |
625 | #ifdef DEBUG |
626 | cout << "Warning: parameter range is bad; curve reversed" << endl; |
627 | #endif |
628 | First = theCurve->ReversedParameter ( First ); |
629 | Last = theCurve->ReversedParameter ( Last ); |
630 | theCurve->Reverse(); |
631 | } |
632 | //pdn 11.01.99 #144 bm1_pe_t4 protection of exceptions in draw |
633 | if (First == Last) { |
634 | First -= Precision::PConfusion(); |
635 | Last += Precision::PConfusion(); |
636 | } |
637 | return Standard_False; |
638 | } |
639 | return Standard_True; |
640 | } |
641 | |
642 | //======================================================================= |
643 | //function : FillBndBox |
644 | //purpose : WORK-AROUND for methods brom BndLib which give not exact bounds |
645 | //======================================================================= |
646 | |
647 | // search for extremum using Newton |
648 | static Standard_Integer SearchForExtremum (const Handle(Geom2d_Curve)& C2d, |
649 | const Standard_Real First, |
650 | const Standard_Real Last, |
651 | const gp_Vec2d &dir, |
652 | Standard_Real &par, |
653 | gp_Pnt2d &res) |
654 | { |
655 | Standard_Real prevpar; |
656 | for ( Standard_Integer i=0; i <10; i++ ) { |
657 | prevpar = par; |
658 | |
659 | gp_Vec2d D1, D2; |
660 | C2d->D2 ( par, res, D1, D2 ); |
661 | Standard_Real Det = ( D2 * dir ); |
662 | if ( Abs ( Det ) < 1e-10 ) return Standard_True; |
663 | |
664 | par -= ( D1 * dir ) / Det; |
665 | if ( Abs ( par - prevpar ) < Precision::PConfusion() ) return Standard_True; |
666 | |
667 | if ( First - par >= Precision::PConfusion() || |
668 | par - Last >= Precision::PConfusion() ) return Standard_False; |
669 | } |
670 | return Standard_True; |
671 | } |
672 | |
673 | void ShapeAnalysis_Curve::FillBndBox (const Handle(Geom2d_Curve)& C2d, |
674 | const Standard_Real First, |
675 | const Standard_Real Last, |
676 | const Standard_Integer NPoints, |
677 | const Standard_Boolean Exact, |
678 | Bnd_Box2d &Box) const |
679 | { |
680 | Standard_Integer nseg = ( NPoints <2 ? 1 : NPoints-1 ); |
681 | Standard_Real step = ( Last - First ) / nseg; |
682 | for ( Standard_Integer i=0; i <= nseg; i++ ) { |
683 | Standard_Real par = First + i * step; |
684 | gp_Pnt2d pnt = C2d->Value ( par ); |
685 | Box.Add ( pnt ); |
686 | if ( ! Exact ) continue; |
687 | |
688 | gp_Pnt2d pextr; |
689 | Standard_Real parextr = par; |
690 | if ( SearchForExtremum ( C2d, Max(First,par-2.*step), Min(Last,par+2.*step), |
691 | gp_Vec2d(1,0), parextr, pextr ) ) { |
692 | Box.Add ( pextr ); |
693 | } |
694 | parextr = par; |
695 | if ( SearchForExtremum ( C2d, Max(First,par-2.*step), Min(Last,par+2.*step), |
696 | gp_Vec2d(0,1), parextr, pextr ) ) { |
697 | Box.Add ( pextr ); |
698 | } |
699 | } |
700 | } |
701 | |
702 | //======================================================================= |
703 | //function : SelectForwardSeam |
704 | //purpose : |
705 | //======================================================================= |
706 | |
707 | Standard_Integer ShapeAnalysis_Curve::SelectForwardSeam(const Handle(Geom2d_Curve)& C1, |
708 | const Handle(Geom2d_Curve)& C2) const |
709 | { |
710 | // SelectForward est destine a devenir un outil distinct |
711 | // Il est sans doute optimisable ! |
712 | |
713 | Standard_Integer theCurveIndice = 0; |
714 | |
715 | Handle(Geom2d_Line) L1 = Handle(Geom2d_Line)::DownCast(C1); |
716 | if (L1.IsNull()) { |
717 | // if we have BoundedCurve, create a line from C1 |
718 | Handle(Geom2d_BoundedCurve) BC1 = Handle(Geom2d_BoundedCurve)::DownCast(C1); |
719 | if (BC1.IsNull()) return theCurveIndice; |
720 | gp_Pnt2d StartBC1 = BC1->StartPoint(); |
721 | gp_Pnt2d EndBC1 = BC1->EndPoint(); |
722 | gp_Vec2d VecBC1(StartBC1, EndBC1); |
723 | L1 = new Geom2d_Line(StartBC1, VecBC1); |
724 | } |
725 | |
726 | Handle(Geom2d_Line) L2 = Handle(Geom2d_Line)::DownCast(C2); |
727 | if (L2.IsNull()) { |
728 | // if we have BoundedCurve, creates a line from C2 |
729 | Handle(Geom2d_BoundedCurve) BC2 = Handle(Geom2d_BoundedCurve)::DownCast(C2); |
730 | if (BC2.IsNull()) return theCurveIndice; |
731 | gp_Pnt2d StartBC2 = BC2->StartPoint(); |
732 | gp_Pnt2d EndBC2 = BC2->EndPoint(); |
733 | gp_Vec2d VecBC2(StartBC2, EndBC2); |
734 | L2 = new Geom2d_Line(StartBC2, VecBC2); |
735 | } |
736 | |
737 | Standard_Boolean UdirPos, UdirNeg, VdirPos, VdirNeg; |
738 | UdirPos = UdirNeg = VdirPos = VdirNeg = Standard_False; |
739 | |
740 | gp_Dir2d theDir = L1->Direction(); |
741 | gp_Pnt2d theLoc1 = L1->Location(); |
742 | gp_Pnt2d theLoc2 = L2->Location(); |
743 | |
744 | if (theDir.X() > 0.) { |
745 | UdirPos = Standard_True; //szv#4:S4163:12Mar99 Udir unused |
746 | } else if (theDir.X() < 0.) { |
747 | UdirNeg = Standard_True; //szv#4:S4163:12Mar99 Udir unused |
748 | } else if (theDir.Y() > 0.) { |
749 | VdirPos = Standard_True; //szv#4:S4163:12Mar99 Vdir unused |
750 | } else if (theDir.Y() < 0.) { |
751 | VdirNeg = Standard_True; //szv#4:S4163:12Mar99 Vdir unused |
752 | } |
753 | |
754 | if (VdirPos) { |
755 | // max of Loc1.X() Loc2.X() |
756 | if (theLoc1.X() > theLoc2.X()) theCurveIndice = 1; |
757 | else theCurveIndice = 2; |
758 | } else if (VdirNeg) { |
759 | if (theLoc1.X() > theLoc2.X()) theCurveIndice = 2; |
760 | else theCurveIndice = 1; |
761 | } else if (UdirPos) { |
762 | // min of Loc1.X() Loc2.X() |
763 | if (theLoc1.Y() < theLoc2.Y()) theCurveIndice = 1; |
764 | else theCurveIndice = 2; |
765 | } else if (UdirNeg) { |
766 | if (theLoc1.Y() < theLoc2.Y()) theCurveIndice = 2; |
767 | else theCurveIndice = 1; |
768 | } |
769 | |
770 | return theCurveIndice; |
771 | } |
772 | |
773 | //%11 pdn 12.01.98 |
774 | //============================================================================= |
775 | // Static methods for IsPlanar |
776 | // IsPlanar |
777 | //============================================================================= |
778 | |
779 | static gp_XYZ GetAnyNormal ( gp_XYZ orig ) |
780 | { |
781 | gp_XYZ Norm; |
782 | if ( Abs ( orig.Z() ) < Precision::Confusion() ) |
783 | Norm.SetCoord ( 0, 0, 1 ); |
784 | else { |
785 | Norm.SetCoord ( orig.Z(), 0, -orig.X() ); |
786 | Standard_Real nrm = Norm.Modulus(); |
787 | if ( nrm < Precision::Confusion() ) Norm.SetCoord ( 0, 0, 1 ); |
788 | else Norm = Norm / nrm; |
789 | } |
790 | return Norm; |
791 | } |
792 | |
793 | //======================================================================= |
794 | //function : GetSamplePoints |
795 | //purpose : |
796 | //======================================================================= |
797 | static void AppendControlPoles (TColgp_SequenceOfPnt& seq, |
798 | const Handle(Geom_Curve) curve) |
799 | { |
800 | if ( curve->IsKind(STANDARD_TYPE(Geom_Line))) { |
801 | seq.Append(curve->Value(0)); |
802 | seq.Append(curve->Value(1)); |
803 | } else if ( curve->IsKind(STANDARD_TYPE(Geom_Conic))) { |
804 | seq.Append(curve->Value(0)); |
805 | seq.Append(curve->Value(PI/2)); |
806 | seq.Append(curve->Value(PI)); |
807 | } else if ( curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) { |
808 | //DeclareAndCast(Geom_TrimmedCurve, Trimmed, curve); |
809 | Handle(Geom_TrimmedCurve) Trimmed = *((Handle(Geom_TrimmedCurve) *) &curve); |
810 | // AppendControlPoles(seq,Trimmed->BasisCurve()); |
811 | Handle(Geom_Curve) aBaseCrv = Trimmed->BasisCurve(); |
812 | Standard_Boolean done = Standard_False; |
813 | if ( aBaseCrv->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) { |
814 | try { |
815 | OCC_CATCH_SIGNALS |
816 | Handle(Geom_Geometry) Ctmp = aBaseCrv->Copy(); |
817 | Handle(Geom_BSplineCurve) bslp = Handle(Geom_BSplineCurve)::DownCast(Ctmp); |
818 | bslp->Segment(curve->FirstParameter(), curve->LastParameter()); |
819 | AppendControlPoles(seq,bslp); |
820 | done = Standard_True; |
821 | } |
822 | catch (Standard_Failure) { |
823 | } |
824 | } |
825 | else if ( aBaseCrv->IsKind(STANDARD_TYPE(Geom_BezierCurve))) { |
826 | try { |
827 | OCC_CATCH_SIGNALS |
828 | Handle(Geom_Geometry) Ctmp = aBaseCrv->Copy(); |
829 | Handle(Geom_BezierCurve) bz = Handle(Geom_BezierCurve)::DownCast(Ctmp); |
830 | bz->Segment(curve->FirstParameter(), curve->LastParameter()); |
831 | AppendControlPoles(seq,bz); |
832 | done = Standard_True; |
833 | } |
834 | catch (Standard_Failure) { |
835 | } |
836 | } |
837 | if (!done) { |
838 | seq.Append(curve->Value(curve->FirstParameter())); |
839 | seq.Append(curve->Value((curve->FirstParameter() + curve->LastParameter())/2.)); |
840 | seq.Append(curve->Value(curve->LastParameter())); |
841 | } |
842 | } else if ( curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) { |
843 | //DeclareAndCast(Geom_OffsetCurve, OffsetC, curve); |
844 | Handle(Geom_OffsetCurve) OffsetC = *((Handle(Geom_OffsetCurve) *) &curve); |
845 | // AppendControlPoles(seq,OffsetC->BasisCurve()); |
846 | seq.Append(curve->Value(curve->FirstParameter())); |
847 | seq.Append(curve->Value((curve->FirstParameter() + curve->LastParameter())/2.)); |
848 | seq.Append(curve->Value(curve->LastParameter())); |
849 | } else if ( curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) { |
850 | //DeclareAndCast(Geom_BSplineCurve, BSpline, curve); |
851 | Handle(Geom_BSplineCurve) BSpline = *((Handle(Geom_BSplineCurve) *) &curve); |
852 | TColgp_Array1OfPnt Poles(1,BSpline->NbPoles()); |
853 | BSpline->Poles(Poles); |
854 | for(Standard_Integer i = 1; i <= BSpline->NbPoles(); i++) |
855 | seq.Append(Poles(i)); |
856 | } else if ( curve->IsKind(STANDARD_TYPE(Geom_BezierCurve))) { |
857 | //DeclareAndCast(Geom_BezierCurve, Bezier, curve); |
858 | //Handle(Geom_BezierCurve) Bezier = Handle(Geom_BezierCurve)::DownCast(curve); |
859 | Handle(Geom_BezierCurve) Bezier = *((Handle(Geom_BezierCurve) *) &curve); |
860 | TColgp_Array1OfPnt Poles(1,Bezier->NbPoles()); |
861 | Bezier->Poles(Poles); |
862 | for(Standard_Integer i = 1; i <= Bezier->NbPoles(); i++) |
863 | seq.Append(Poles(i)); |
864 | } |
865 | } |
866 | |
867 | //%11 pdn 12.01.98 |
868 | //szv modified |
869 | //======================================================================= |
870 | //function : IsPlanar |
871 | //purpose : Detects if points lie in some plane and returns normal |
872 | //======================================================================= |
873 | |
874 | Standard_Boolean ShapeAnalysis_Curve::IsPlanar (const TColgp_Array1OfPnt& pnts, |
875 | gp_XYZ& Normal, |
876 | const Standard_Real preci) |
877 | { |
878 | Standard_Real precision = (preci > 0.0)? preci : Precision::Confusion(); |
879 | Standard_Boolean noNorm = (Normal.SquareModulus() == 0); |
880 | |
881 | if (pnts.Length() < 3) { |
882 | gp_XYZ N1 = pnts(1).XYZ()-pnts(2).XYZ(); |
883 | if (noNorm) { |
884 | Normal = GetAnyNormal(N1); |
885 | return Standard_True; |
886 | } |
887 | return Abs(N1*Normal) < Precision::Confusion(); |
888 | } |
889 | |
890 | gp_XYZ aMaxDir; |
891 | if (noNorm) { |
892 | //define a center point |
893 | gp_XYZ aCenter(0,0,0); |
894 | Standard_Integer i = 1; |
895 | for (; i <= pnts.Length(); i++) |
896 | aCenter += pnts(i).XYZ(); |
897 | aCenter/=pnts.Length(); |
898 | |
899 | |
900 | aMaxDir = pnts(1).XYZ() - aCenter; |
901 | Normal = (pnts(pnts.Length()).XYZ() - aCenter) ^ aMaxDir; |
902 | |
903 | for ( i = 1; i < pnts.Length(); i++) { |
904 | gp_XYZ aTmpDir = pnts(i+1).XYZ() - aCenter; |
905 | if(aTmpDir.SquareModulus() > aMaxDir.SquareModulus()) |
906 | aMaxDir = aTmpDir; |
907 | |
908 | gp_XYZ aDelta = (pnts(i).XYZ() - aCenter) ^ (pnts(i+1).XYZ() - aCenter); |
909 | if(Normal*aDelta < 0) |
910 | aDelta*=-1; |
911 | Normal += aDelta; |
912 | } |
913 | } |
914 | |
915 | // check if points are linear |
916 | Standard_Real nrm = Normal.Modulus(); |
917 | if ( nrm < Precision::Confusion() ) { |
918 | Normal = GetAnyNormal(aMaxDir); |
919 | return Standard_True; |
920 | } |
921 | Normal = Normal / nrm; |
922 | |
923 | Standard_Real mind = RealLast(), maxd = -RealLast(), dev; |
924 | for (Standard_Integer i = 1; i <= pnts.Length(); i++) { |
925 | dev = pnts(i).XYZ() * Normal; |
926 | if (dev < mind) mind = dev; |
927 | if (dev > maxd) maxd = dev; |
928 | } |
929 | |
930 | return ((maxd - mind) <= precision); |
931 | } |
932 | |
933 | |
934 | //======================================================================= |
935 | //function : IsPlanar |
936 | //purpose : |
937 | //======================================================================= |
938 | |
939 | Standard_Boolean ShapeAnalysis_Curve::IsPlanar (const Handle(Geom_Curve)& curve, |
940 | gp_XYZ& Normal, |
941 | const Standard_Real preci) |
942 | { |
943 | Standard_Real precision = (preci > 0.0)? preci : Precision::Confusion(); |
944 | Standard_Boolean noNorm = (Normal.SquareModulus() == 0); |
945 | |
946 | if (curve->IsKind(STANDARD_TYPE(Geom_Line))) { |
947 | //DeclareAndCast(Geom_Line, Line, curve); |
948 | Handle(Geom_Line) Line = *((Handle(Geom_Line) *) &curve); |
949 | gp_XYZ N1 = Line->Position().Direction().XYZ(); |
950 | if (noNorm) { |
951 | Normal = GetAnyNormal(N1); |
952 | return Standard_True; |
953 | } |
954 | return Abs(N1*Normal) < Precision::Confusion(); |
955 | } |
956 | |
957 | if (curve->IsKind(STANDARD_TYPE(Geom_Conic))) { |
958 | //DeclareAndCast(Geom_Conic, Conic, curve); |
959 | Handle(Geom_Conic) Conic = *((Handle(Geom_Conic) *) &curve); |
960 | gp_XYZ N1 = Conic->Axis().Direction().XYZ(); |
961 | if (noNorm) { |
962 | Normal = N1; |
963 | return Standard_True; |
964 | } |
965 | gp_XYZ aVecMul = N1^Normal; |
966 | return aVecMul.SquareModulus() < Precision::Confusion()*Precision::Confusion(); |
967 | } |
968 | |
969 | if (curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) { |
970 | //DeclareAndCast(Geom_TrimmedCurve, Trimmed, curve); |
971 | Handle(Geom_TrimmedCurve) Trimmed = *((Handle(Geom_TrimmedCurve) *) &curve); |
972 | return IsPlanar(Trimmed->BasisCurve(),Normal,precision); |
973 | } |
974 | |
975 | if (curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) { |
976 | //DeclareAndCast(Geom_OffsetCurve, OffsetC, curve); |
977 | Handle(Geom_OffsetCurve) OffsetC = *((Handle(Geom_OffsetCurve) *) &curve); |
978 | return IsPlanar(OffsetC->BasisCurve(),Normal,precision); |
979 | } |
980 | |
981 | if (curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) { |
982 | //DeclareAndCast(Geom_BSplineCurve, BSpline, curve); |
983 | Handle(Geom_BSplineCurve) BSpline = *((Handle(Geom_BSplineCurve) *) &curve); |
984 | TColgp_Array1OfPnt Poles(1,BSpline->NbPoles()); |
985 | BSpline->Poles(Poles); |
986 | return IsPlanar(Poles,Normal,precision); |
987 | } |
988 | |
989 | if (curve->IsKind(STANDARD_TYPE(Geom_BezierCurve))) { |
990 | //DeclareAndCast(Geom_BezierCurve, Bezier, curve); |
991 | Handle(Geom_BezierCurve) Bezier = *((Handle(Geom_BezierCurve) *) &curve); |
992 | TColgp_Array1OfPnt Poles(1,Bezier->NbPoles()); |
993 | Bezier->Poles(Poles); |
994 | return IsPlanar(Poles,Normal,precision); |
995 | } |
996 | |
997 | if (curve->IsKind(STANDARD_TYPE(ShapeExtend_ComplexCurve))) { |
998 | //DeclareAndCast(ShapeExtend_ComplexCurve, Complex, curve); |
999 | Handle(ShapeExtend_ComplexCurve) Complex = *((Handle(ShapeExtend_ComplexCurve) *) &curve); |
1000 | TColgp_SequenceOfPnt sequence; |
1001 | Standard_Integer i; // svv Jan11 2000 : porting on DEC |
1002 | for (i = 1; i <= Complex->NbCurves(); i++) |
1003 | AppendControlPoles(sequence,Complex->Curve(i)); |
1004 | TColgp_Array1OfPnt Poles(1,sequence.Length()); |
1005 | for (i=1; i <= sequence.Length(); i++) Poles(i) = sequence(i); |
1006 | return IsPlanar(Poles,Normal,precision); |
1007 | } |
1008 | |
1009 | return Standard_False; |
1010 | } |
1011 | |
1012 | //======================================================================= |
1013 | //function : GetSamplePoints |
1014 | //purpose : |
1015 | //======================================================================= |
1016 | |
1017 | Standard_Boolean ShapeAnalysis_Curve::GetSamplePoints (const Handle(Geom_Curve)& curve, |
1018 | const Standard_Real first, |
1019 | const Standard_Real last, |
1020 | TColgp_SequenceOfPnt& seq) |
1021 | { |
1022 | Standard_Real adelta = curve->LastParameter() - curve->FirstParameter(); |
1023 | if(!adelta ) |
1024 | return Standard_False; |
1025 | |
1026 | Standard_Integer aK = (Standard_Integer)ceil ((last - first) / adelta); |
1027 | Standard_Integer nbp =100*aK; |
1028 | if(curve->IsKind(STANDARD_TYPE(Geom_Line))) |
1029 | nbp =2; |
1030 | else if(curve->IsKind(STANDARD_TYPE(Geom_Circle))) |
1031 | nbp =360*aK; |
1032 | |
1033 | else if (curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) { |
1034 | Handle(Geom_BSplineCurve) aBspl = Handle(Geom_BSplineCurve)::DownCast(curve); |
1035 | |
1036 | nbp = aBspl->NbKnots() * aBspl->Degree()*aK; |
1037 | if(nbp < 2.0) nbp=2; |
1038 | } |
1039 | else if (curve->IsKind(STANDARD_TYPE(Geom_BezierCurve))) { |
1040 | Handle(Geom_BezierCurve) aB = Handle(Geom_BezierCurve)::DownCast(curve); |
1041 | nbp = 3 + aB->NbPoles(); |
1042 | } |
1043 | else if(curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) { |
1044 | Handle(Geom_OffsetCurve) aC = Handle(Geom_OffsetCurve)::DownCast(curve); |
1045 | return GetSamplePoints(aC->BasisCurve(),first,last,seq); |
1046 | } |
1047 | else if(curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) { |
1048 | Handle(Geom_TrimmedCurve) aC = Handle(Geom_TrimmedCurve)::DownCast(curve); |
1049 | return GetSamplePoints(aC->BasisCurve(),first,last,seq); |
1050 | } |
1051 | Standard_Real step = ( last - first ) / (Standard_Real)( nbp - 1 ); |
1052 | Standard_Real par = first, stop = last - 0.5 * step; |
1053 | for ( ; par < stop; par += step ) |
1054 | seq.Append(curve->Value(par)); |
1055 | seq.Append(curve->Value(last)); |
1056 | return Standard_True; |
1057 | } |
1058 | //======================================================================= |
1059 | //function : GetSamplePoints |
1060 | //purpose : |
1061 | //======================================================================= |
1062 | |
1063 | Standard_Boolean ShapeAnalysis_Curve::GetSamplePoints (const Handle(Geom2d_Curve)& curve, |
1064 | const Standard_Real first, |
1065 | const Standard_Real last, |
1066 | TColgp_SequenceOfPnt2d& seq) |
1067 | { |
1068 | //:abv 05.06.02: TUBE.stp |
1069 | // Use the same distribution of points as BRepTopAdaptor_FClass2d for consistency |
1070 | Geom2dAdaptor_Curve C ( curve, first, last ); |
1071 | Standard_Integer nbs = Geom2dInt_Geom2dCurveTool::NbSamples(C); |
1072 | //-- Attention aux bsplines rationnelles de degree 3. (bouts de cercles entre autres) |
1073 | if (nbs > 2) nbs*=4; |
1074 | Standard_Real step = ( last - first ) / (Standard_Real)( nbs - 1 ); |
1075 | Standard_Real par = first, stop = last - 0.5 * step; |
1076 | for ( ; par < stop; par += step ) |
1077 | seq.Append(curve->Value(par)); |
1078 | seq.Append(curve->Value(last)); |
1079 | return Standard_True; |
1080 | /* |
1081 | Standard_Integer i; |
1082 | Standard_Real step; |
1083 | gp_Pnt2d Ptmp; |
1084 | if ( curve->IsKind(STANDARD_TYPE(Geom2d_Line))) { |
1085 | seq.Append(curve->Value(first)); |
1086 | seq.Append(curve->Value(last)); |
1087 | return Standard_True; |
1088 | } |
1089 | else if(curve->IsKind(STANDARD_TYPE(Geom2d_Conic))) { |
1090 | step = Min ( PI, last-first ) / 19; //:abv 05.06.02 TUBE.stp #19209...: PI/16 |
1091 | // if( step>(last-first) ) { |
1092 | // seq.Append(curve->Value(first)); |
1093 | // seq.Append(curve->Value((last+first)/2)); |
1094 | // seq.Append(curve->Value(last)); |
1095 | // return Standard_True; |
1096 | // } |
1097 | // else { |
1098 | Standard_Real par=first; |
1099 | for(i=0; par<last; i++) { |
1100 | seq.Append(curve->Value(par)); |
1101 | par += step; |
1102 | } |
1103 | seq.Append(curve->Value(last)); |
1104 | return Standard_True; |
1105 | // } |
1106 | } |
1107 | else if ( curve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) { |
1108 | DeclareAndCast(Geom2d_TrimmedCurve, Trimmed, curve); |
1109 | return GetControlPoints(Trimmed->BasisCurve(), seq, first, last); |
1110 | } |
1111 | else if ( curve->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) { |
1112 | DeclareAndCast(Geom2d_BSplineCurve, aBs, curve); |
1113 | TColStd_SequenceOfReal aSeqParam; |
1114 | if(!aBs.IsNull()) { |
1115 | aSeqParam.Append(first); |
1116 | for(i=1; i<=aBs->NbKnots(); i++) { |
1117 | if( aBs->Knot(i)>first && aBs->Knot(i)<last ) |
1118 | aSeqParam.Append(aBs->Knot(i)); |
1119 | } |
1120 | aSeqParam.Append(last); |
1121 | Standard_Integer NbPoints=aBs->Degree(); |
1122 | if( (aSeqParam.Length()-1)*NbPoints>10 ) { |
1123 | for(i=1; i<aSeqParam.Length(); i++) { |
1124 | Standard_Real FirstPar = aSeqParam.Value(i); |
1125 | Standard_Real LastPar = aSeqParam.Value(i+1); |
1126 | step = (LastPar-FirstPar)/NbPoints; |
1127 | for(Standard_Integer k=0; k<NbPoints; k++ ) { |
1128 | aBs->D0(FirstPar+step*k, Ptmp); |
1129 | seq.Append(Ptmp); |
1130 | } |
1131 | } |
1132 | aBs->D0(last, Ptmp); |
1133 | seq.Append(Ptmp); |
1134 | return Standard_True; |
1135 | } |
1136 | else { |
1137 | step = (last-first)/10; |
1138 | for(Standard_Integer k=0; k<=10; k++ ) { |
1139 | aBs->D0(first+step*k, Ptmp); |
1140 | seq.Append(Ptmp); |
1141 | } |
1142 | return Standard_True; |
1143 | } |
1144 | } |
1145 | } |
1146 | else if ( curve->IsKind(STANDARD_TYPE(Geom2d_BezierCurve))) { |
1147 | DeclareAndCast(Geom2d_BezierCurve, aBz, curve); |
1148 | if(!aBz.IsNull()) { |
1149 | Standard_Integer NbPoints=aBz->Degree(); |
1150 | step = (last-first)/NbPoints; |
1151 | for(Standard_Integer k=0; k<NbPoints; k++ ) { |
1152 | aBz->D0(first+step*k, Ptmp); |
1153 | seq.Append(Ptmp); |
1154 | } |
1155 | aBz->D0(last, Ptmp); |
1156 | seq.Append(Ptmp); |
1157 | return Standard_True; |
1158 | } |
1159 | } |
1160 | return Standard_False; |
1161 | */ |
1162 | } |
1163 | |
1164 | //======================================================================= |
1165 | //function : IsClosed |
1166 | //purpose : |
1167 | //======================================================================= |
1168 | |
1169 | Standard_Boolean ShapeAnalysis_Curve::IsClosed(const Handle(Geom_Curve)& theCurve, |
1170 | const Standard_Real preci) |
1171 | { |
1172 | if (theCurve->IsClosed()) |
1173 | return Standard_True; |
1174 | |
1175 | Standard_Real prec = Max (preci, Precision::Confusion()); |
1176 | |
1177 | Standard_Real f, l; |
1178 | f = theCurve->FirstParameter(); |
1179 | l = theCurve->LastParameter(); |
1180 | |
1181 | if (Precision::IsInfinite (f) || Precision::IsInfinite (l)) |
1182 | return Standard_False; |
1183 | |
1184 | Standard_Real aClosedVal = theCurve->Value(f).SquareDistance(theCurve->Value(l)); |
1185 | Standard_Real preci2 = prec*prec; |
1186 | |
1187 | return (aClosedVal <= preci2); |
1188 | } |
1189 | //======================================================================= |
1190 | //function : IsPeriodic |
1191 | //purpose : OCC996 |
1192 | //======================================================================= |
1193 | |
1194 | Standard_Boolean ShapeAnalysis_Curve::IsPeriodic(const Handle(Geom_Curve)& theCurve) |
1195 | { |
1196 | // 15.11.2002 PTV OCC966 |
1197 | // remove regressions in DE tests (diva, divb, divc, toe3) in KAS:dev |
1198 | // ask IsPeriodic on BasisCurve |
1199 | Handle(Geom_Curve) aTmpCurve = theCurve; |
1200 | while ( (aTmpCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) || |
1201 | (aTmpCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) ) { |
1202 | if (aTmpCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) |
1203 | aTmpCurve = Handle(Geom_OffsetCurve)::DownCast(aTmpCurve)->BasisCurve(); |
1204 | if (aTmpCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) |
1205 | aTmpCurve = Handle(Geom_TrimmedCurve)::DownCast(aTmpCurve)->BasisCurve(); |
1206 | } |
1207 | return aTmpCurve->IsPeriodic(); |
1208 | } |
1209 | |
1210 | Standard_Boolean ShapeAnalysis_Curve::IsPeriodic(const Handle(Geom2d_Curve)& theCurve) |
1211 | { |
1212 | // 15.11.2002 PTV OCC966 |
1213 | // remove regressions in DE tests (diva, divb, divc, toe3) in KAS:dev |
1214 | // ask IsPeriodic on BasisCurve |
1215 | Handle(Geom2d_Curve) aTmpCurve = theCurve; |
1216 | while ( (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve))) || |
1217 | (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) ) { |
1218 | if (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve))) |
1219 | aTmpCurve = Handle(Geom2d_OffsetCurve)::DownCast(aTmpCurve)->BasisCurve(); |
1220 | if (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) |
1221 | aTmpCurve = Handle(Geom2d_TrimmedCurve)::DownCast(aTmpCurve)->BasisCurve(); |
1222 | } |
1223 | return aTmpCurve->IsPeriodic(); |
1224 | } |