1 // Copyright (c) 1999-2012 OPEN CASCADE SAS
3 // The content of this file is subject to the Open CASCADE Technology Public
4 // License Version 6.5 (the "License"). You may not use the content of this file
5 // except in compliance with the License. Please obtain a copy of the License
6 // at http://www.opencascade.org and read it completely before using this file.
8 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
9 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11 // The Original Code and all software distributed under the License is
12 // distributed on an "AS IS" basis, without warranty of any kind, and the
13 // Initial Developer hereby disclaims all such warranties, including without
14 // limitation, any warranties of merchantability, fitness for a particular
15 // purpose or non-infringement. Please see the License for the specific terms
16 // and conditions governing the rights and limitations under the License.
18 // pdn 04.12.98 Add method using Adaptor_Curve
19 //:j8 abv 10.12.98 TR10 r0501_db.stp #9423
20 //pdn 25.12.98 private method ProjectAct
22 //:s5 abv 22.04.99 Adding debug printouts in catch {} blocks
23 // abv 14.05.99 S4174: Adding method for exact computing of the boundary box
24 // gka 21.06.99 S4208: adding method NextProject(Adaptor_Curve)
25 // msv 30.05.00 correct IsPlanar for a conic curve
26 #include <ShapeAnalysis_Curve.ixx>
30 #include <Geom2d_BoundedCurve.hxx>
31 #include <Geom2d_Line.hxx>
32 #include <Geom_BSplineCurve.hxx>
33 #include <GeomAdaptor_Curve.hxx>
35 #include <Precision.hxx>
37 #include <Standard_ErrorHandler.hxx>
38 #include <Standard_Failure.hxx>
39 #include <Adaptor3d_Curve.hxx>
40 #include <Extrema_ExtPC.hxx>
41 #include <ShapeAnalysis.hxx>
42 #include <TColgp_SequenceOfPnt.hxx>
43 #include <Geom_Line.hxx>
44 #include <Geom_Conic.hxx>
45 #include <Geom_TrimmedCurve.hxx>
46 #include <Geom_OffsetCurve.hxx>
47 #include <Geom_BezierCurve.hxx>
48 #include <ShapeExtend_ComplexCurve.hxx>
49 #include <Geom2d_Conic.hxx>
50 #include <Geom2d_TrimmedCurve.hxx>
51 #include <Geom2d_BSplineCurve.hxx>
52 #include <Geom2d_BezierCurve.hxx>
54 #include <Geom2d_OffsetCurve.hxx>
55 #include <Geom2dInt_Geom2dCurveTool.hxx>
56 #include <Geom2dAdaptor_Curve.hxx>
57 #include <Geom_Circle.hxx>
58 #include <Extrema_LocateExtPC.hxx>
60 //=======================================================================
61 //function : ProjectOnSegments
63 //=======================================================================
65 static void ProjectOnSegments (const Adaptor3d_Curve& AC, const gp_Pnt& P3D,
66 const Standard_Integer nbseg,
67 Standard_Real& uMin, Standard_Real& uMax,
68 Standard_Real& distmin, gp_Pnt& proj, Standard_Real& param)
70 // On considere <nbseg> points sur [uMin,uMax]
71 // Quel est le plus proche. Et quel est le nouvel intervalle
72 // (il ne peut pas deborder l ancien)
73 Standard_Real u, dist, delta = (nbseg == 0)? 0 : (uMax-uMin)/nbseg; //szv#4:S4163:12Mar99 anti-exception
74 for (Standard_Integer i = 0; i <= nbseg; i ++) {
75 u = uMin + (delta * i);
76 gp_Pnt PU = AC.Value (u);
77 dist = PU.Distance (P3D);
78 if (dist < distmin) { distmin = dist; proj = PU; param = u; }
82 cout<<"ShapeAnalysis_Geom:Project, param="<<param<<" -> distmin="<<distmin<<endl;
85 uMax = Min (uMax, param+delta);
86 uMin = Max (uMin, param-delta);
90 //=======================================================================
93 //=======================================================================
95 Standard_Real ShapeAnalysis_Curve::Project(const Handle(Geom_Curve)& C3D,
97 const Standard_Real preci,
100 const Standard_Boolean AdjustToEnds) const
102 Standard_Real uMin = C3D->FirstParameter();
103 Standard_Real uMax = C3D->LastParameter();
104 if (uMin < uMax) return Project (C3D,P3D,preci,proj,param,uMin,uMax,AdjustToEnds);
105 else return Project (C3D,P3D,preci,proj,param,uMax,uMin,AdjustToEnds);
108 //=======================================================================
111 //=======================================================================
113 Standard_Real ShapeAnalysis_Curve::Project(const Handle(Geom_Curve)& C3D,
115 const Standard_Real preci,
117 Standard_Real& param,
118 const Standard_Real cf,
119 const Standard_Real cl,
120 const Standard_Boolean AdjustToEnds) const
122 Standard_Real distmin;
123 Standard_Real uMin = (cf < cl ? cf : cl);
124 Standard_Real uMax = (cf < cl ? cl : cf);
126 if (C3D->IsKind(STANDARD_TYPE(Geom_BoundedCurve))) {
127 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
128 gp_Pnt LowBound = C3D->Value(uMin);
129 gp_Pnt HigBound = C3D->Value(uMax);
130 distmin = LowBound.Distance(P3D);
131 if (distmin <= prec) {
136 distmin = HigBound.Distance(P3D);
137 if (distmin <= prec) {
144 GeomAdaptor_Curve GAC(C3D, uMin, uMax);
145 if (!C3D->IsClosed()) {
146 //modified by rln on 16/12/97 after CSR# PRO11641 entity 20767
147 //the VIso was not closed (according to C3D->IsClosed()) while it "almost"
148 //was (the distance between ends of the curve was a little bit more than
149 //Precision::Confusion())
150 //in that case value 0.1 was too much and this method returned not correct parameter
153 // modified by pdn on 01.07.98 after BUC60195 entity 1952 (Min() added)
154 Standard_Real delta = Min (GAC.Resolution (preci), (uMax - uMin) * 0.1);
157 GAC.Load(C3D, uMin, uMax);
160 return ProjectAct(GAC, P3D, preci, proj, param);
163 //=======================================================================
166 //=======================================================================
168 Standard_Real ShapeAnalysis_Curve::Project(const Adaptor3d_Curve& C3D,
170 const Standard_Real preci,
172 Standard_Real& param,
173 const Standard_Boolean AdjustToEnds) const
176 Standard_Real uMin = C3D.FirstParameter();
177 Standard_Real uMax = C3D.LastParameter();
178 Standard_Real distmin;
179 if (!Precision::IsInfinite(uMin)||!Precision::IsInfinite(uMax)) {
180 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
181 gp_Pnt LowBound = C3D.Value(uMin);
182 gp_Pnt HigBound = C3D.Value(uMax);
183 distmin = LowBound.Distance(P3D);
184 if (distmin <= prec) {
189 distmin = HigBound.Distance(P3D);
190 if (distmin <= prec) {
196 return ProjectAct(C3D, P3D, preci, proj, param);
199 //=======================================================================
200 //function : ProjectAct
202 //=======================================================================
204 Standard_Real ShapeAnalysis_Curve::ProjectAct(const Adaptor3d_Curve& C3D,
206 const Standard_Real preci,
208 Standard_Real& param) const
211 Standard_Boolean OK = Standard_False;
214 Extrema_ExtPC myExtPC(P3D,C3D);
215 if ( myExtPC.IsDone() && ( myExtPC.NbExt() > 0) ) {
216 Standard_Real dist2, dist2Min = myExtPC.SquareDistance(1);
217 Standard_Integer index = 1;
218 for ( Standard_Integer i = 2; i <= myExtPC.NbExt(); i++) {
219 dist2 = myExtPC.SquareDistance(i);
220 if ( dist2 < dist2Min) { dist2Min = dist2; index = i; }
222 param = (myExtPC.Point(index)).Parameter();
223 proj = (myExtPC.Point(index)).Value();
227 catch(Standard_Failure) {
230 cout << "\nWarning: ShapeAnalysis_Curve::ProjectAct(): Exception in Extrema_ExtPC: ";
231 Standard_Failure::Caught()->Print(cout); cout << endl;
235 //szv#4:S4163:12Mar99 moved
236 Standard_Real uMin = C3D.FirstParameter(), uMax = C3D.LastParameter();
237 Standard_Boolean closed = Standard_False; // si on franchit les bornes ...
238 Standard_Real distmin = RealLast(), valclosed = 0.;
239 Standard_Real aModParam = param;
240 Standard_Real aModMin = distmin;
242 // PTV 29.05.2002 remember the old solution, cause it could be better
243 Standard_Real anOldParam =0.;
244 Standard_Boolean IsHaveOldSol = Standard_False;
247 IsHaveOldSol = Standard_True;
250 distmin = proj.Distance (P3D);
252 if (distmin > preci) OK = Standard_False;
253 // Cas TrimmedCurve a cheval. Voir la courbe de base.
254 // Si fermee, passer une periode
255 if (C3D.IsClosed()) {
256 closed = Standard_True;
257 valclosed = uMax - uMin; //szv#4:S4163:12Mar99 optimized
262 // BUG NICOLAS - Si le point est sur la courbe 0 Solutions
263 // Cela fonctionne avec ElCLib
265 // D une facon generale, on essaie de TOUJOURS retourner un resultat
266 // MEME PAS BIEN BON. L appelant pourra decider alors quoi faire
269 switch(C3D.GetType()) {
272 const gp_Circ& aCirc = C3D.Circle();
273 proj = aCirc.Position().Location();
274 if(aCirc.Radius() <= gp::Resolution() ||
275 P3D.SquareDistance(proj) <= gp::Resolution() ) {
276 param = C3D.FirstParameter();
277 proj = proj.XYZ() + aCirc.XAxis().Direction().XYZ() * aCirc.Radius();
280 param = ElCLib::Parameter(aCirc, P3D);
281 proj = ElCLib::Value(param, aCirc);
283 closed = Standard_True;
287 case GeomAbs_Hyperbola:
289 param = ElCLib::Parameter(C3D.Hyperbola(), P3D);
290 proj = ElCLib::Value(param, C3D.Hyperbola());
293 case GeomAbs_Parabola:
295 param = ElCLib::Parameter(C3D.Parabola(), P3D);
296 proj = ElCLib::Value(param, C3D.Parabola());
301 param = ElCLib::Parameter(C3D.Line(), P3D);
302 proj = ElCLib::Value(param, C3D.Line());
305 case GeomAbs_Ellipse:
307 param = ElCLib::Parameter(C3D.Ellipse(), P3D);
308 proj = ElCLib::Value(param, C3D.Ellipse());
309 closed = Standard_True;
316 // on ne va quand meme pas se laisser abattre ... ???
317 // on tente ceci : 21 points sur la courbe, quel est le plus proche
318 distmin = Precision::Infinite();
319 ProjectOnSegments (C3D,P3D,25,uMin,uMax,distmin,proj,param);
320 if (distmin <= preci)
322 Extrema_LocateExtPC aProjector (P3D, C3D, param/*U0*/, uMin, uMax, preci/*TolU*/);
323 if (aProjector.IsDone())
325 param = aProjector.Point().Parameter();
326 proj = aProjector.Point().Value();
327 Standard_Real aDistNewton = P3D.Distance(proj);
328 if (aDistNewton < aModMin)
331 // cout <<"newton failed"<<endl;
332 ProjectOnSegments (C3D,P3D,40,uMin,uMax,distmin,proj,param);
333 if (distmin <= preci) return distmin;
334 ProjectOnSegments (C3D,P3D,20,uMin,uMax,distmin,proj,param);
335 if (distmin <= preci) return distmin;
336 ProjectOnSegments (C3D,P3D,25,uMin,uMax,distmin,proj,param);
337 if (distmin <= preci) return distmin;
338 ProjectOnSegments (C3D,P3D,40,uMin,uMax,distmin,proj,param);
339 if (distmin <= preci) return distmin;
340 // soyons raisonnable ...
341 if(distmin > aModMin) {
351 // p = PPOC.LowerDistanceParameter(); cf try
352 if ( closed && ( param < uMin || param > uMax ) )
353 param += ShapeAnalysis::AdjustByPeriod ( param, 0.5 * ( uMin + uMax ), valclosed );
356 // PTV 29.05.2002 Compare old solution and new;
357 Standard_Real adist1, adist2;
358 adist1 = anOldProj.SquareDistance(P3D);
359 adist2 = proj.SquareDistance (P3D);
360 if (adist1 < adist2) {
365 return proj.Distance (P3D);
369 //=======================================================================
370 //function : NextProject
371 //purpose : Newton algo for projecting point on curve (S4030)
372 //=======================================================================
374 Standard_Real ShapeAnalysis_Curve::NextProject(const Standard_Real paramPrev,
375 const Handle(Geom_Curve)& C3D,
377 const Standard_Real preci,
379 Standard_Real& param,
380 const Standard_Real cf,
381 const Standard_Real cl,
382 const Standard_Boolean AdjustToEnds) const
384 Standard_Real uMin = (cf < cl ? cf : cl);
385 Standard_Real uMax = (cf < cl ? cl : cf);
386 Standard_Real distmin;
387 if (C3D->IsKind(STANDARD_TYPE(Geom_BoundedCurve))) {
388 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
389 gp_Pnt LowBound = C3D->Value(uMin);
390 gp_Pnt HigBound = C3D->Value(uMax);
391 distmin = LowBound.Distance(P3D);
392 if (distmin <= prec) {
397 distmin = HigBound.Distance(P3D);
398 if (distmin <= prec) {
405 GeomAdaptor_Curve GAC(C3D, uMin, uMax);
406 if (!C3D->IsClosed()) {
407 //modified by rln on 16/12/97 after CSR# PRO11641 entity 20767
408 //the VIso was not closed (according to C3D->IsClosed()) while it "almost"
409 //was (the distance between ends of the curve was a little bit more than
410 //Precision::Confusion())
411 //in that case value 0.1 was too much and this method returned not correct parameter
414 // modified by pdn on 01.07.98 after BUC60195 entity 1952 (Min() added)
415 Standard_Real delta = Min (GAC.Resolution (preci), (uMax - uMin) * 0.1);
418 GAC.Load(C3D, uMin, uMax);
420 return NextProject ( paramPrev, GAC, P3D, preci, proj, param );
423 //=======================================================================
424 //function : NextProject
426 //=======================================================================
428 Standard_Real ShapeAnalysis_Curve::NextProject(const Standard_Real paramPrev,
429 const Adaptor3d_Curve& C3D,
431 const Standard_Real preci,
433 Standard_Real& param) const
435 Standard_Real uMin = C3D.FirstParameter();
436 Standard_Real uMax = C3D.LastParameter();
438 Extrema_LocateExtPC aProjector (P3D, C3D, paramPrev/*U0*/, uMin, uMax, preci/*TolU*/);
439 if (aProjector.IsDone()){
440 param = aProjector.Point().Parameter();
441 proj = aProjector.Point().Value();
442 return P3D.Distance(proj);
444 return Project(C3D, P3D, preci, proj, param, Standard_False);
447 //=======================================================================
448 //function : AdjustParameters
449 //purpose : Copied from StepToTopoDS_GeometricTuul::UpdateParam3d (Aug 2001)
450 //=======================================================================
452 Standard_Boolean ShapeAnalysis_Curve::ValidateRange (const Handle(Geom_Curve)& theCurve,
453 Standard_Real& First, Standard_Real& Last,
454 const Standard_Real preci) const
456 // First et/ou Last peuvent etre en dehors des bornes naturelles de la courbe.
457 // On donnera alors la valeur en bout a First et/ou Last
459 Standard_Real cf = theCurve->FirstParameter();
460 Standard_Real cl = theCurve->LastParameter();
461 // Standard_Real preci = BRepAPI::Precision();
463 if (theCurve->IsKind(STANDARD_TYPE(Geom_BoundedCurve)) && !theCurve->IsClosed()) {
466 cout << "Update Edge First Parameter to Curve First Parameter" << endl;
470 else if (First > cl) {
472 cout << "Update Edge First Parameter to Curve Last Parameter" << endl;
478 cout << "Update Edge Last Parameter to Curve First Parameter" << endl;
482 else if (Last > cl) {
484 cout << "Update Edge Last Parameter to Curve Last Parameter" << endl;
490 if (First < Last) return Standard_True;
492 // 15.11.2002 PTV OCC966
493 if (ShapeAnalysis_Curve::IsPeriodic(theCurve))
494 ElCLib::AdjustPeriodic(cf,cl,Precision::PConfusion(),First,Last); //:a7 abv 11 Feb 98: preci -> PConfusion()
495 else if (theCurve->IsClosed()) {
496 // l'un des points projecte se trouve sur l'origine du parametrage
497 // de la courbe 3D. L algo a donne cl +- preci au lieu de cf ou vice-versa
498 // DANGER precision 3d applique a une espace 1d
500 // Last = cf au lieu de Last = cl
501 if (Abs(Last - cf) < Precision::PConfusion() /*preci*/) Last = cl ;
502 // First = cl au lieu de First = cf
503 else if (Abs(First - cl) < Precision::PConfusion() /*preci*/) First = cf;
505 // on se trouve dans un cas ou l origine est traversee
506 // illegal sur une courbe fermee non periodique
507 // on inverse quand meme les parametres !!!!!!
509 //:S4136 abv 20 Apr 99: r0701_ug.stp #6230: add check in 3d
510 if ( theCurve->Value(First).Distance(theCurve->Value(cf)) < preci ) First = cf;
511 if ( theCurve->Value(Last).Distance(theCurve->Value(cl)) < preci ) Last = cl;
512 if ( First > Last ) {
514 cout << "Warning : parameter range of edge crossing non periodic curve origin" << endl;
516 Standard_Real tmp = First;
522 // The curve is closed within the 3D tolerance
523 else if (theCurve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
524 Handle(Geom_BSplineCurve) aBSpline =
525 Handle(Geom_BSplineCurve)::DownCast(theCurve);
526 if (aBSpline->StartPoint().Distance(aBSpline->EndPoint()) <= preci ) {
527 //:S4136 <= BRepAPI::Precision()) {
528 // l'un des points projecte se trouve sur l'origine du parametrage
529 // de la courbe 3D. L algo a donne cl +- preci au lieu de cf ou vice-versa
530 // DANGER precision 3d applique a une espace 1d
532 // Last = cf au lieu de Last = cl
533 if (Abs(Last - cf) < Precision::PConfusion() /*preci*/) Last = cl ;
534 // First = cl au lieu de First = cf
535 else if (Abs(First - cl) < Precision::PConfusion() /*preci*/) First = cf;
537 // on se trouve dans un cas ou l origine est traversee
538 // illegal sur une courbe fermee non periodique
539 // on inverse quand meme les parametres !!!!!!
542 cout << "Warning : parameter range of edge crossing non periodic curve origin" << endl;
544 Standard_Real tmp = First;
549 //abv 15.03.00 #72 bm1_pe_t4 protection of exceptions in draw
550 else if ( First > Last ) {
552 cout << "Warning: parameter range is bad; curve reversed" << endl;
554 First = theCurve->ReversedParameter ( First );
555 Last = theCurve->ReversedParameter ( Last );
558 //:j9 abv 11 Dec 98: PRO7747 #4875, after :j8: else
559 if (First == Last) { //gka 10.07.1998 file PRO7656 entity 33334
560 First = cf; Last = cl;
561 return Standard_False;
566 cout << "UpdateParam3d Failed" << endl;
567 cout << " - Curve Type : " << theCurve->DynamicType() << endl;
568 cout << " - Param 1 : " << First << endl;
569 cout << " - Param 2 : " << Last << endl;
571 //abv 15.03.00 #72 bm1_pe_t4 protection of exceptions in draw
572 if ( First > Last ) {
574 cout << "Warning: parameter range is bad; curve reversed" << endl;
576 First = theCurve->ReversedParameter ( First );
577 Last = theCurve->ReversedParameter ( Last );
580 //pdn 11.01.99 #144 bm1_pe_t4 protection of exceptions in draw
582 First -= Precision::PConfusion();
583 Last += Precision::PConfusion();
585 return Standard_False;
587 return Standard_True;
590 //=======================================================================
591 //function : FillBndBox
592 //purpose : WORK-AROUND for methods brom BndLib which give not exact bounds
593 //=======================================================================
595 // search for extremum using Newton
596 static Standard_Integer SearchForExtremum (const Handle(Geom2d_Curve)& C2d,
597 const Standard_Real First,
598 const Standard_Real Last,
603 Standard_Real prevpar;
604 for ( Standard_Integer i=0; i <10; i++ ) {
608 C2d->D2 ( par, res, D1, D2 );
609 Standard_Real Det = ( D2 * dir );
610 if ( Abs ( Det ) < 1e-10 ) return Standard_True;
612 par -= ( D1 * dir ) / Det;
613 if ( Abs ( par - prevpar ) < Precision::PConfusion() ) return Standard_True;
615 if ( First - par >= Precision::PConfusion() ||
616 par - Last >= Precision::PConfusion() ) return Standard_False;
618 return Standard_True;
621 void ShapeAnalysis_Curve::FillBndBox (const Handle(Geom2d_Curve)& C2d,
622 const Standard_Real First,
623 const Standard_Real Last,
624 const Standard_Integer NPoints,
625 const Standard_Boolean Exact,
626 Bnd_Box2d &Box) const
628 Standard_Integer nseg = ( NPoints <2 ? 1 : NPoints-1 );
629 Standard_Real step = ( Last - First ) / nseg;
630 for ( Standard_Integer i=0; i <= nseg; i++ ) {
631 Standard_Real par = First + i * step;
632 gp_Pnt2d pnt = C2d->Value ( par );
634 if ( ! Exact ) continue;
637 Standard_Real parextr = par;
638 if ( SearchForExtremum ( C2d, Max(First,par-2.*step), Min(Last,par+2.*step),
639 gp_Vec2d(1,0), parextr, pextr ) ) {
643 if ( SearchForExtremum ( C2d, Max(First,par-2.*step), Min(Last,par+2.*step),
644 gp_Vec2d(0,1), parextr, pextr ) ) {
650 //=======================================================================
651 //function : SelectForwardSeam
653 //=======================================================================
655 Standard_Integer ShapeAnalysis_Curve::SelectForwardSeam(const Handle(Geom2d_Curve)& C1,
656 const Handle(Geom2d_Curve)& C2) const
658 // SelectForward est destine a devenir un outil distinct
659 // Il est sans doute optimisable !
661 Standard_Integer theCurveIndice = 0;
663 Handle(Geom2d_Line) L1 = Handle(Geom2d_Line)::DownCast(C1);
665 // if we have BoundedCurve, create a line from C1
666 Handle(Geom2d_BoundedCurve) BC1 = Handle(Geom2d_BoundedCurve)::DownCast(C1);
667 if (BC1.IsNull()) return theCurveIndice;
668 gp_Pnt2d StartBC1 = BC1->StartPoint();
669 gp_Pnt2d EndBC1 = BC1->EndPoint();
670 gp_Vec2d VecBC1(StartBC1, EndBC1);
671 L1 = new Geom2d_Line(StartBC1, VecBC1);
674 Handle(Geom2d_Line) L2 = Handle(Geom2d_Line)::DownCast(C2);
676 // if we have BoundedCurve, creates a line from C2
677 Handle(Geom2d_BoundedCurve) BC2 = Handle(Geom2d_BoundedCurve)::DownCast(C2);
678 if (BC2.IsNull()) return theCurveIndice;
679 gp_Pnt2d StartBC2 = BC2->StartPoint();
680 gp_Pnt2d EndBC2 = BC2->EndPoint();
681 gp_Vec2d VecBC2(StartBC2, EndBC2);
682 L2 = new Geom2d_Line(StartBC2, VecBC2);
685 Standard_Boolean UdirPos, UdirNeg, VdirPos, VdirNeg;
686 UdirPos = UdirNeg = VdirPos = VdirNeg = Standard_False;
688 gp_Dir2d theDir = L1->Direction();
689 gp_Pnt2d theLoc1 = L1->Location();
690 gp_Pnt2d theLoc2 = L2->Location();
692 if (theDir.X() > 0.) {
693 UdirPos = Standard_True; //szv#4:S4163:12Mar99 Udir unused
694 } else if (theDir.X() < 0.) {
695 UdirNeg = Standard_True; //szv#4:S4163:12Mar99 Udir unused
696 } else if (theDir.Y() > 0.) {
697 VdirPos = Standard_True; //szv#4:S4163:12Mar99 Vdir unused
698 } else if (theDir.Y() < 0.) {
699 VdirNeg = Standard_True; //szv#4:S4163:12Mar99 Vdir unused
703 // max of Loc1.X() Loc2.X()
704 if (theLoc1.X() > theLoc2.X()) theCurveIndice = 1;
705 else theCurveIndice = 2;
706 } else if (VdirNeg) {
707 if (theLoc1.X() > theLoc2.X()) theCurveIndice = 2;
708 else theCurveIndice = 1;
709 } else if (UdirPos) {
710 // min of Loc1.X() Loc2.X()
711 if (theLoc1.Y() < theLoc2.Y()) theCurveIndice = 1;
712 else theCurveIndice = 2;
713 } else if (UdirNeg) {
714 if (theLoc1.Y() < theLoc2.Y()) theCurveIndice = 2;
715 else theCurveIndice = 1;
718 return theCurveIndice;
722 //=============================================================================
723 // Static methods for IsPlanar
725 //=============================================================================
727 static gp_XYZ GetAnyNormal ( gp_XYZ orig )
730 if ( Abs ( orig.Z() ) < Precision::Confusion() )
731 Norm.SetCoord ( 0, 0, 1 );
733 Norm.SetCoord ( orig.Z(), 0, -orig.X() );
734 Standard_Real nrm = Norm.Modulus();
735 if ( nrm < Precision::Confusion() ) Norm.SetCoord ( 0, 0, 1 );
736 else Norm = Norm / nrm;
741 //=======================================================================
742 //function : GetSamplePoints
744 //=======================================================================
745 static void AppendControlPoles (TColgp_SequenceOfPnt& seq,
746 const Handle(Geom_Curve) curve)
748 if ( curve->IsKind(STANDARD_TYPE(Geom_Line))) {
749 seq.Append(curve->Value(0));
750 seq.Append(curve->Value(1));
751 } else if ( curve->IsKind(STANDARD_TYPE(Geom_Conic))) {
752 seq.Append(curve->Value(0));
753 seq.Append(curve->Value(M_PI/2));
754 seq.Append(curve->Value(M_PI));
755 } else if ( curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
756 //DeclareAndCast(Geom_TrimmedCurve, Trimmed, curve);
757 Handle(Geom_TrimmedCurve) Trimmed = *((Handle(Geom_TrimmedCurve) *) &curve);
758 // AppendControlPoles(seq,Trimmed->BasisCurve());
759 Handle(Geom_Curve) aBaseCrv = Trimmed->BasisCurve();
760 Standard_Boolean done = Standard_False;
761 if ( aBaseCrv->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
764 Handle(Geom_Geometry) Ctmp = aBaseCrv->Copy();
765 Handle(Geom_BSplineCurve) bslp = Handle(Geom_BSplineCurve)::DownCast(Ctmp);
766 bslp->Segment(curve->FirstParameter(), curve->LastParameter());
767 AppendControlPoles(seq,bslp);
768 done = Standard_True;
770 catch (Standard_Failure) {
773 else if ( aBaseCrv->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
776 Handle(Geom_Geometry) Ctmp = aBaseCrv->Copy();
777 Handle(Geom_BezierCurve) bz = Handle(Geom_BezierCurve)::DownCast(Ctmp);
778 bz->Segment(curve->FirstParameter(), curve->LastParameter());
779 AppendControlPoles(seq,bz);
780 done = Standard_True;
782 catch (Standard_Failure) {
786 seq.Append(curve->Value(curve->FirstParameter()));
787 seq.Append(curve->Value((curve->FirstParameter() + curve->LastParameter())/2.));
788 seq.Append(curve->Value(curve->LastParameter()));
790 } else if ( curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
791 //DeclareAndCast(Geom_OffsetCurve, OffsetC, curve);
792 Handle(Geom_OffsetCurve) OffsetC = *((Handle(Geom_OffsetCurve) *) &curve);
793 // AppendControlPoles(seq,OffsetC->BasisCurve());
794 seq.Append(curve->Value(curve->FirstParameter()));
795 seq.Append(curve->Value((curve->FirstParameter() + curve->LastParameter())/2.));
796 seq.Append(curve->Value(curve->LastParameter()));
797 } else if ( curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
798 //DeclareAndCast(Geom_BSplineCurve, BSpline, curve);
799 Handle(Geom_BSplineCurve) BSpline = *((Handle(Geom_BSplineCurve) *) &curve);
800 TColgp_Array1OfPnt Poles(1,BSpline->NbPoles());
801 BSpline->Poles(Poles);
802 for(Standard_Integer i = 1; i <= BSpline->NbPoles(); i++)
803 seq.Append(Poles(i));
804 } else if ( curve->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
805 //DeclareAndCast(Geom_BezierCurve, Bezier, curve);
806 //Handle(Geom_BezierCurve) Bezier = Handle(Geom_BezierCurve)::DownCast(curve);
807 Handle(Geom_BezierCurve) Bezier = *((Handle(Geom_BezierCurve) *) &curve);
808 TColgp_Array1OfPnt Poles(1,Bezier->NbPoles());
809 Bezier->Poles(Poles);
810 for(Standard_Integer i = 1; i <= Bezier->NbPoles(); i++)
811 seq.Append(Poles(i));
817 //=======================================================================
818 //function : IsPlanar
819 //purpose : Detects if points lie in some plane and returns normal
820 //=======================================================================
822 Standard_Boolean ShapeAnalysis_Curve::IsPlanar (const TColgp_Array1OfPnt& pnts,
824 const Standard_Real preci)
826 Standard_Real precision = (preci > 0.0)? preci : Precision::Confusion();
827 Standard_Boolean noNorm = (Normal.SquareModulus() == 0);
829 if (pnts.Length() < 3) {
830 gp_XYZ N1 = pnts(1).XYZ()-pnts(2).XYZ();
832 Normal = GetAnyNormal(N1);
833 return Standard_True;
835 return Abs(N1*Normal) < Precision::Confusion();
840 //define a center point
841 gp_XYZ aCenter(0,0,0);
842 Standard_Integer i = 1;
843 for (; i <= pnts.Length(); i++)
844 aCenter += pnts(i).XYZ();
845 aCenter/=pnts.Length();
848 aMaxDir = pnts(1).XYZ() - aCenter;
849 Normal = (pnts(pnts.Length()).XYZ() - aCenter) ^ aMaxDir;
851 for ( i = 1; i < pnts.Length(); i++) {
852 gp_XYZ aTmpDir = pnts(i+1).XYZ() - aCenter;
853 if(aTmpDir.SquareModulus() > aMaxDir.SquareModulus())
856 gp_XYZ aDelta = (pnts(i).XYZ() - aCenter) ^ (pnts(i+1).XYZ() - aCenter);
857 if(Normal*aDelta < 0)
863 // check if points are linear
864 Standard_Real nrm = Normal.Modulus();
865 if ( nrm < Precision::Confusion() ) {
866 Normal = GetAnyNormal(aMaxDir);
867 return Standard_True;
869 Normal = Normal / nrm;
871 Standard_Real mind = RealLast(), maxd = -RealLast(), dev;
872 for (Standard_Integer i = 1; i <= pnts.Length(); i++) {
873 dev = pnts(i).XYZ() * Normal;
874 if (dev < mind) mind = dev;
875 if (dev > maxd) maxd = dev;
878 return ((maxd - mind) <= precision);
882 //=======================================================================
883 //function : IsPlanar
885 //=======================================================================
887 Standard_Boolean ShapeAnalysis_Curve::IsPlanar (const Handle(Geom_Curve)& curve,
889 const Standard_Real preci)
891 Standard_Real precision = (preci > 0.0)? preci : Precision::Confusion();
892 Standard_Boolean noNorm = (Normal.SquareModulus() == 0);
894 if (curve->IsKind(STANDARD_TYPE(Geom_Line))) {
895 //DeclareAndCast(Geom_Line, Line, curve);
896 Handle(Geom_Line) Line = *((Handle(Geom_Line) *) &curve);
897 gp_XYZ N1 = Line->Position().Direction().XYZ();
899 Normal = GetAnyNormal(N1);
900 return Standard_True;
902 return Abs(N1*Normal) < Precision::Confusion();
905 if (curve->IsKind(STANDARD_TYPE(Geom_Conic))) {
906 //DeclareAndCast(Geom_Conic, Conic, curve);
907 Handle(Geom_Conic) Conic = *((Handle(Geom_Conic) *) &curve);
908 gp_XYZ N1 = Conic->Axis().Direction().XYZ();
911 return Standard_True;
913 gp_XYZ aVecMul = N1^Normal;
914 return aVecMul.SquareModulus() < Precision::SquareConfusion();
917 if (curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
918 //DeclareAndCast(Geom_TrimmedCurve, Trimmed, curve);
919 Handle(Geom_TrimmedCurve) Trimmed = *((Handle(Geom_TrimmedCurve) *) &curve);
920 return IsPlanar(Trimmed->BasisCurve(),Normal,precision);
923 if (curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
924 //DeclareAndCast(Geom_OffsetCurve, OffsetC, curve);
925 Handle(Geom_OffsetCurve) OffsetC = *((Handle(Geom_OffsetCurve) *) &curve);
926 return IsPlanar(OffsetC->BasisCurve(),Normal,precision);
929 if (curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
930 //DeclareAndCast(Geom_BSplineCurve, BSpline, curve);
931 Handle(Geom_BSplineCurve) BSpline = *((Handle(Geom_BSplineCurve) *) &curve);
932 TColgp_Array1OfPnt Poles(1,BSpline->NbPoles());
933 BSpline->Poles(Poles);
934 return IsPlanar(Poles,Normal,precision);
937 if (curve->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
938 //DeclareAndCast(Geom_BezierCurve, Bezier, curve);
939 Handle(Geom_BezierCurve) Bezier = *((Handle(Geom_BezierCurve) *) &curve);
940 TColgp_Array1OfPnt Poles(1,Bezier->NbPoles());
941 Bezier->Poles(Poles);
942 return IsPlanar(Poles,Normal,precision);
945 if (curve->IsKind(STANDARD_TYPE(ShapeExtend_ComplexCurve))) {
946 //DeclareAndCast(ShapeExtend_ComplexCurve, Complex, curve);
947 Handle(ShapeExtend_ComplexCurve) Complex = *((Handle(ShapeExtend_ComplexCurve) *) &curve);
948 TColgp_SequenceOfPnt sequence;
949 Standard_Integer i; // svv Jan11 2000 : porting on DEC
950 for (i = 1; i <= Complex->NbCurves(); i++)
951 AppendControlPoles(sequence,Complex->Curve(i));
952 TColgp_Array1OfPnt Poles(1,sequence.Length());
953 for (i=1; i <= sequence.Length(); i++) Poles(i) = sequence(i);
954 return IsPlanar(Poles,Normal,precision);
957 return Standard_False;
960 //=======================================================================
961 //function : GetSamplePoints
963 //=======================================================================
965 Standard_Boolean ShapeAnalysis_Curve::GetSamplePoints (const Handle(Geom_Curve)& curve,
966 const Standard_Real first,
967 const Standard_Real last,
968 TColgp_SequenceOfPnt& seq)
970 Standard_Real adelta = curve->LastParameter() - curve->FirstParameter();
972 return Standard_False;
974 Standard_Integer aK = (Standard_Integer)ceil ((last - first) / adelta);
975 Standard_Integer nbp =100*aK;
976 if(curve->IsKind(STANDARD_TYPE(Geom_Line)))
978 else if(curve->IsKind(STANDARD_TYPE(Geom_Circle)))
981 else if (curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
982 Handle(Geom_BSplineCurve) aBspl = Handle(Geom_BSplineCurve)::DownCast(curve);
984 nbp = aBspl->NbKnots() * aBspl->Degree()*aK;
987 else if (curve->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
988 Handle(Geom_BezierCurve) aB = Handle(Geom_BezierCurve)::DownCast(curve);
989 nbp = 3 + aB->NbPoles();
991 else if(curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
992 Handle(Geom_OffsetCurve) aC = Handle(Geom_OffsetCurve)::DownCast(curve);
993 return GetSamplePoints(aC->BasisCurve(),first,last,seq);
995 else if(curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
996 Handle(Geom_TrimmedCurve) aC = Handle(Geom_TrimmedCurve)::DownCast(curve);
997 return GetSamplePoints(aC->BasisCurve(),first,last,seq);
999 Standard_Real step = ( last - first ) / (Standard_Real)( nbp - 1 );
1000 Standard_Real par = first, stop = last - 0.5 * step;
1001 for ( ; par < stop; par += step )
1002 seq.Append(curve->Value(par));
1003 seq.Append(curve->Value(last));
1004 return Standard_True;
1006 //=======================================================================
1007 //function : GetSamplePoints
1009 //=======================================================================
1011 Standard_Boolean ShapeAnalysis_Curve::GetSamplePoints (const Handle(Geom2d_Curve)& curve,
1012 const Standard_Real first,
1013 const Standard_Real last,
1014 TColgp_SequenceOfPnt2d& seq)
1016 //:abv 05.06.02: TUBE.stp
1017 // Use the same distribution of points as BRepTopAdaptor_FClass2d for consistency
1018 Geom2dAdaptor_Curve C ( curve, first, last );
1019 Standard_Integer nbs = Geom2dInt_Geom2dCurveTool::NbSamples(C);
1020 //-- Attention aux bsplines rationnelles de degree 3. (bouts de cercles entre autres)
1021 if (nbs > 2) nbs*=4;
1022 Standard_Real step = ( last - first ) / (Standard_Real)( nbs - 1 );
1023 Standard_Real par = first, stop = last - 0.5 * step;
1024 for ( ; par < stop; par += step )
1025 seq.Append(curve->Value(par));
1026 seq.Append(curve->Value(last));
1027 return Standard_True;
1032 if ( curve->IsKind(STANDARD_TYPE(Geom2d_Line))) {
1033 seq.Append(curve->Value(first));
1034 seq.Append(curve->Value(last));
1035 return Standard_True;
1037 else if(curve->IsKind(STANDARD_TYPE(Geom2d_Conic))) {
1038 step = Min ( M_PI, last-first ) / 19; //:abv 05.06.02 TUBE.stp #19209...: M_PI/16
1039 // if( step>(last-first) ) {
1040 // seq.Append(curve->Value(first));
1041 // seq.Append(curve->Value((last+first)/2));
1042 // seq.Append(curve->Value(last));
1043 // return Standard_True;
1046 Standard_Real par=first;
1047 for(i=0; par<last; i++) {
1048 seq.Append(curve->Value(par));
1051 seq.Append(curve->Value(last));
1052 return Standard_True;
1055 else if ( curve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) {
1056 DeclareAndCast(Geom2d_TrimmedCurve, Trimmed, curve);
1057 return GetControlPoints(Trimmed->BasisCurve(), seq, first, last);
1059 else if ( curve->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) {
1060 DeclareAndCast(Geom2d_BSplineCurve, aBs, curve);
1061 TColStd_SequenceOfReal aSeqParam;
1063 aSeqParam.Append(first);
1064 for(i=1; i<=aBs->NbKnots(); i++) {
1065 if( aBs->Knot(i)>first && aBs->Knot(i)<last )
1066 aSeqParam.Append(aBs->Knot(i));
1068 aSeqParam.Append(last);
1069 Standard_Integer NbPoints=aBs->Degree();
1070 if( (aSeqParam.Length()-1)*NbPoints>10 ) {
1071 for(i=1; i<aSeqParam.Length(); i++) {
1072 Standard_Real FirstPar = aSeqParam.Value(i);
1073 Standard_Real LastPar = aSeqParam.Value(i+1);
1074 step = (LastPar-FirstPar)/NbPoints;
1075 for(Standard_Integer k=0; k<NbPoints; k++ ) {
1076 aBs->D0(FirstPar+step*k, Ptmp);
1080 aBs->D0(last, Ptmp);
1082 return Standard_True;
1085 step = (last-first)/10;
1086 for(Standard_Integer k=0; k<=10; k++ ) {
1087 aBs->D0(first+step*k, Ptmp);
1090 return Standard_True;
1094 else if ( curve->IsKind(STANDARD_TYPE(Geom2d_BezierCurve))) {
1095 DeclareAndCast(Geom2d_BezierCurve, aBz, curve);
1097 Standard_Integer NbPoints=aBz->Degree();
1098 step = (last-first)/NbPoints;
1099 for(Standard_Integer k=0; k<NbPoints; k++ ) {
1100 aBz->D0(first+step*k, Ptmp);
1103 aBz->D0(last, Ptmp);
1105 return Standard_True;
1108 return Standard_False;
1112 //=======================================================================
1113 //function : IsClosed
1115 //=======================================================================
1117 Standard_Boolean ShapeAnalysis_Curve::IsClosed(const Handle(Geom_Curve)& theCurve,
1118 const Standard_Real preci)
1120 if (theCurve->IsClosed())
1121 return Standard_True;
1123 Standard_Real prec = Max (preci, Precision::Confusion());
1126 f = theCurve->FirstParameter();
1127 l = theCurve->LastParameter();
1129 if (Precision::IsInfinite (f) || Precision::IsInfinite (l))
1130 return Standard_False;
1132 Standard_Real aClosedVal = theCurve->Value(f).SquareDistance(theCurve->Value(l));
1133 Standard_Real preci2 = prec*prec;
1135 return (aClosedVal <= preci2);
1137 //=======================================================================
1138 //function : IsPeriodic
1140 //=======================================================================
1142 Standard_Boolean ShapeAnalysis_Curve::IsPeriodic(const Handle(Geom_Curve)& theCurve)
1144 // 15.11.2002 PTV OCC966
1145 // remove regressions in DE tests (diva, divb, divc, toe3) in KAS:dev
1146 // ask IsPeriodic on BasisCurve
1147 Handle(Geom_Curve) aTmpCurve = theCurve;
1148 while ( (aTmpCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) ||
1149 (aTmpCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) ) {
1150 if (aTmpCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
1151 aTmpCurve = Handle(Geom_OffsetCurve)::DownCast(aTmpCurve)->BasisCurve();
1152 if (aTmpCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
1153 aTmpCurve = Handle(Geom_TrimmedCurve)::DownCast(aTmpCurve)->BasisCurve();
1155 return aTmpCurve->IsPeriodic();
1158 Standard_Boolean ShapeAnalysis_Curve::IsPeriodic(const Handle(Geom2d_Curve)& theCurve)
1160 // 15.11.2002 PTV OCC966
1161 // remove regressions in DE tests (diva, divb, divc, toe3) in KAS:dev
1162 // ask IsPeriodic on BasisCurve
1163 Handle(Geom2d_Curve) aTmpCurve = theCurve;
1164 while ( (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve))) ||
1165 (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) ) {
1166 if (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
1167 aTmpCurve = Handle(Geom2d_OffsetCurve)::DownCast(aTmpCurve)->BasisCurve();
1168 if (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
1169 aTmpCurve = Handle(Geom2d_TrimmedCurve)::DownCast(aTmpCurve)->BasisCurve();
1171 return aTmpCurve->IsPeriodic();