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, dist2, delta = (nbseg == 0)? 0 : (uMax-uMin)/nbseg; //szv#4:S4163:12Mar99 anti-exception
74 Standard_Real distmin2 = distmin * distmin;
75 Standard_Boolean aHasChanged = Standard_False;
76 for (Standard_Integer i = 0; i <= nbseg; i ++) {
77 u = uMin + (delta * i);
78 gp_Pnt PU = AC.Value (u);
79 dist2 = PU.SquareDistance (P3D);
80 if (dist2 < distmin2) { distmin2 = dist2; proj = PU; param = u; aHasChanged = Standard_True; }
83 distmin = Sqrt (distmin2);
85 cout<<"ShapeAnalysis_Geom:Project, param="<<param<<" -> distmin="<<distmin<<endl;
88 uMax = Min (uMax, param+delta);
89 uMin = Max (uMin, param-delta);
93 //=======================================================================
96 //=======================================================================
98 Standard_Real ShapeAnalysis_Curve::Project(const Handle(Geom_Curve)& C3D,
100 const Standard_Real preci,
102 Standard_Real& param,
103 const Standard_Boolean AdjustToEnds) const
105 Standard_Real uMin = C3D->FirstParameter();
106 Standard_Real uMax = C3D->LastParameter();
107 if (uMin < uMax) return Project (C3D,P3D,preci,proj,param,uMin,uMax,AdjustToEnds);
108 else return Project (C3D,P3D,preci,proj,param,uMax,uMin,AdjustToEnds);
111 //=======================================================================
114 //=======================================================================
116 Standard_Real ShapeAnalysis_Curve::Project(const Handle(Geom_Curve)& C3D,
118 const Standard_Real preci,
120 Standard_Real& param,
121 const Standard_Real cf,
122 const Standard_Real cl,
123 const Standard_Boolean AdjustToEnds) const
125 Standard_Real distmin;
126 Standard_Real uMin = (cf < cl ? cf : cl);
127 Standard_Real uMax = (cf < cl ? cl : cf);
129 if (C3D->IsKind(STANDARD_TYPE(Geom_BoundedCurve))) {
130 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
131 gp_Pnt LowBound = C3D->Value(uMin);
132 gp_Pnt HigBound = C3D->Value(uMax);
133 distmin = LowBound.Distance(P3D);
134 if (distmin <= prec) {
139 distmin = HigBound.Distance(P3D);
140 if (distmin <= prec) {
147 GeomAdaptor_Curve GAC(C3D, uMin, uMax);
148 if (!C3D->IsClosed()) {
149 //modified by rln on 16/12/97 after CSR# PRO11641 entity 20767
150 //the VIso was not closed (according to C3D->IsClosed()) while it "almost"
151 //was (the distance between ends of the curve was a little bit more than
152 //Precision::Confusion())
153 //in that case value 0.1 was too much and this method returned not correct parameter
156 // modified by pdn on 01.07.98 after BUC60195 entity 1952 (Min() added)
157 Standard_Real delta = Min (GAC.Resolution (preci), (uMax - uMin) * 0.1);
160 GAC.Load(C3D, uMin, uMax);
163 return ProjectAct(GAC, P3D, preci, proj, param);
166 //=======================================================================
169 //=======================================================================
171 Standard_Real ShapeAnalysis_Curve::Project(const Adaptor3d_Curve& C3D,
173 const Standard_Real preci,
175 Standard_Real& param,
176 const Standard_Boolean AdjustToEnds) const
179 Standard_Real uMin = C3D.FirstParameter();
180 Standard_Real uMax = C3D.LastParameter();
181 Standard_Real distmin;
182 if (!Precision::IsInfinite(uMin)||!Precision::IsInfinite(uMax)) {
183 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
184 gp_Pnt LowBound = C3D.Value(uMin);
185 gp_Pnt HigBound = C3D.Value(uMax);
186 distmin = LowBound.Distance(P3D);
187 if (distmin <= prec) {
192 distmin = HigBound.Distance(P3D);
193 if (distmin <= prec) {
199 return ProjectAct(C3D, P3D, preci, proj, param);
202 //=======================================================================
203 //function : ProjectAct
205 //=======================================================================
207 Standard_Real ShapeAnalysis_Curve::ProjectAct(const Adaptor3d_Curve& C3D,
209 const Standard_Real preci,
211 Standard_Real& param) const
214 Standard_Boolean OK = Standard_False;
217 Extrema_ExtPC myExtPC(P3D,C3D);
218 if ( myExtPC.IsDone() && ( myExtPC.NbExt() > 0) ) {
219 Standard_Real dist2, dist2Min = myExtPC.SquareDistance(1);
220 Standard_Integer index = 1;
221 for ( Standard_Integer i = 2; i <= myExtPC.NbExt(); i++) {
222 dist2 = myExtPC.SquareDistance(i);
223 if ( dist2 < dist2Min) { dist2Min = dist2; index = i; }
225 param = (myExtPC.Point(index)).Parameter();
226 proj = (myExtPC.Point(index)).Value();
230 catch(Standard_Failure) {
233 cout << "\nWarning: ShapeAnalysis_Curve::ProjectAct(): Exception in Extrema_ExtPC: ";
234 Standard_Failure::Caught()->Print(cout); cout << endl;
238 //szv#4:S4163:12Mar99 moved
239 Standard_Real uMin = C3D.FirstParameter(), uMax = C3D.LastParameter();
240 Standard_Boolean closed = Standard_False; // si on franchit les bornes ...
241 Standard_Real distmin = RealLast(), valclosed = 0.;
242 Standard_Real aModParam = param;
243 Standard_Real aModMin = distmin;
245 // PTV 29.05.2002 remember the old solution, cause it could be better
246 Standard_Real anOldParam =0.;
247 Standard_Boolean IsHaveOldSol = Standard_False;
250 IsHaveOldSol = Standard_True;
253 distmin = proj.Distance (P3D);
255 if (distmin > preci) OK = Standard_False;
256 // Cas TrimmedCurve a cheval. Voir la courbe de base.
257 // Si fermee, passer une periode
258 if (C3D.IsClosed()) {
259 closed = Standard_True;
260 valclosed = uMax - uMin; //szv#4:S4163:12Mar99 optimized
265 // BUG NICOLAS - Si le point est sur la courbe 0 Solutions
266 // Cela fonctionne avec ElCLib
268 // D une facon generale, on essaie de TOUJOURS retourner un resultat
269 // MEME PAS BIEN BON. L appelant pourra decider alors quoi faire
272 switch(C3D.GetType()) {
275 const gp_Circ& aCirc = C3D.Circle();
276 proj = aCirc.Position().Location();
277 if(aCirc.Radius() <= gp::Resolution() ||
278 P3D.SquareDistance(proj) <= gp::Resolution() ) {
279 param = C3D.FirstParameter();
280 proj = proj.XYZ() + aCirc.XAxis().Direction().XYZ() * aCirc.Radius();
283 param = ElCLib::Parameter(aCirc, P3D);
284 proj = ElCLib::Value(param, aCirc);
286 closed = Standard_True;
290 case GeomAbs_Hyperbola:
292 param = ElCLib::Parameter(C3D.Hyperbola(), P3D);
293 proj = ElCLib::Value(param, C3D.Hyperbola());
296 case GeomAbs_Parabola:
298 param = ElCLib::Parameter(C3D.Parabola(), P3D);
299 proj = ElCLib::Value(param, C3D.Parabola());
304 param = ElCLib::Parameter(C3D.Line(), P3D);
305 proj = ElCLib::Value(param, C3D.Line());
308 case GeomAbs_Ellipse:
310 param = ElCLib::Parameter(C3D.Ellipse(), P3D);
311 proj = ElCLib::Value(param, C3D.Ellipse());
312 closed = Standard_True;
319 // on ne va quand meme pas se laisser abattre ... ???
320 // on tente ceci : 21 points sur la courbe, quel est le plus proche
321 distmin = Precision::Infinite();
322 ProjectOnSegments (C3D,P3D,25,uMin,uMax,distmin,proj,param);
323 if (distmin <= preci)
325 Extrema_LocateExtPC aProjector (P3D, C3D, param/*U0*/, uMin, uMax, preci/*TolU*/);
326 if (aProjector.IsDone())
328 param = aProjector.Point().Parameter();
329 proj = aProjector.Point().Value();
330 Standard_Real aDistNewton = P3D.Distance(proj);
331 if (aDistNewton < aModMin)
334 // cout <<"newton failed"<<endl;
335 ProjectOnSegments (C3D,P3D,40,uMin,uMax,distmin,proj,param);
336 if (distmin <= preci) return distmin;
337 ProjectOnSegments (C3D,P3D,20,uMin,uMax,distmin,proj,param);
338 if (distmin <= preci) return distmin;
339 ProjectOnSegments (C3D,P3D,25,uMin,uMax,distmin,proj,param);
340 if (distmin <= preci) return distmin;
341 ProjectOnSegments (C3D,P3D,40,uMin,uMax,distmin,proj,param);
342 if (distmin <= preci) return distmin;
343 // soyons raisonnable ...
344 if(distmin > aModMin) {
354 // p = PPOC.LowerDistanceParameter(); cf try
355 if ( closed && ( param < uMin || param > uMax ) )
356 param += ShapeAnalysis::AdjustByPeriod ( param, 0.5 * ( uMin + uMax ), valclosed );
359 // PTV 29.05.2002 Compare old solution and new;
360 Standard_Real adist1, adist2;
361 adist1 = anOldProj.SquareDistance(P3D);
362 adist2 = proj.SquareDistance (P3D);
363 if (adist1 < adist2) {
368 return proj.Distance (P3D);
372 //=======================================================================
373 //function : NextProject
374 //purpose : Newton algo for projecting point on curve (S4030)
375 //=======================================================================
377 Standard_Real ShapeAnalysis_Curve::NextProject(const Standard_Real paramPrev,
378 const Handle(Geom_Curve)& C3D,
380 const Standard_Real preci,
382 Standard_Real& param,
383 const Standard_Real cf,
384 const Standard_Real cl,
385 const Standard_Boolean AdjustToEnds) const
387 Standard_Real uMin = (cf < cl ? cf : cl);
388 Standard_Real uMax = (cf < cl ? cl : cf);
389 Standard_Real distmin;
390 if (C3D->IsKind(STANDARD_TYPE(Geom_BoundedCurve))) {
391 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
392 gp_Pnt LowBound = C3D->Value(uMin);
393 gp_Pnt HigBound = C3D->Value(uMax);
394 distmin = LowBound.Distance(P3D);
395 if (distmin <= prec) {
400 distmin = HigBound.Distance(P3D);
401 if (distmin <= prec) {
408 GeomAdaptor_Curve GAC(C3D, uMin, uMax);
409 if (!C3D->IsClosed()) {
410 //modified by rln on 16/12/97 after CSR# PRO11641 entity 20767
411 //the VIso was not closed (according to C3D->IsClosed()) while it "almost"
412 //was (the distance between ends of the curve was a little bit more than
413 //Precision::Confusion())
414 //in that case value 0.1 was too much and this method returned not correct parameter
417 // modified by pdn on 01.07.98 after BUC60195 entity 1952 (Min() added)
418 Standard_Real delta = Min (GAC.Resolution (preci), (uMax - uMin) * 0.1);
421 GAC.Load(C3D, uMin, uMax);
423 return NextProject ( paramPrev, GAC, P3D, preci, proj, param );
426 //=======================================================================
427 //function : NextProject
429 //=======================================================================
431 Standard_Real ShapeAnalysis_Curve::NextProject(const Standard_Real paramPrev,
432 const Adaptor3d_Curve& C3D,
434 const Standard_Real preci,
436 Standard_Real& param) const
438 Standard_Real uMin = C3D.FirstParameter();
439 Standard_Real uMax = C3D.LastParameter();
441 Extrema_LocateExtPC aProjector (P3D, C3D, paramPrev/*U0*/, uMin, uMax, preci/*TolU*/);
442 if (aProjector.IsDone()){
443 param = aProjector.Point().Parameter();
444 proj = aProjector.Point().Value();
445 return P3D.Distance(proj);
447 return Project(C3D, P3D, preci, proj, param, Standard_False);
450 //=======================================================================
451 //function : AdjustParameters
452 //purpose : Copied from StepToTopoDS_GeometricTuul::UpdateParam3d (Aug 2001)
453 //=======================================================================
455 Standard_Boolean ShapeAnalysis_Curve::ValidateRange (const Handle(Geom_Curve)& theCurve,
456 Standard_Real& First, Standard_Real& Last,
457 const Standard_Real preci) const
459 // First et/ou Last peuvent etre en dehors des bornes naturelles de la courbe.
460 // On donnera alors la valeur en bout a First et/ou Last
462 Standard_Real cf = theCurve->FirstParameter();
463 Standard_Real cl = theCurve->LastParameter();
464 // Standard_Real preci = BRepAPI::Precision();
466 if (theCurve->IsKind(STANDARD_TYPE(Geom_BoundedCurve)) && !theCurve->IsClosed()) {
469 cout << "Update Edge First Parameter to Curve First Parameter" << endl;
473 else if (First > cl) {
475 cout << "Update Edge First Parameter to Curve Last Parameter" << endl;
481 cout << "Update Edge Last Parameter to Curve First Parameter" << endl;
485 else if (Last > cl) {
487 cout << "Update Edge Last Parameter to Curve Last Parameter" << endl;
493 if (First < Last) return Standard_True;
495 // 15.11.2002 PTV OCC966
496 if (ShapeAnalysis_Curve::IsPeriodic(theCurve))
497 ElCLib::AdjustPeriodic(cf,cl,Precision::PConfusion(),First,Last); //:a7 abv 11 Feb 98: preci -> PConfusion()
498 else if (theCurve->IsClosed()) {
499 // l'un des points projecte se trouve sur l'origine du parametrage
500 // de la courbe 3D. L algo a donne cl +- preci au lieu de cf ou vice-versa
501 // DANGER precision 3d applique a une espace 1d
503 // Last = cf au lieu de Last = cl
504 if (Abs(Last - cf) < Precision::PConfusion() /*preci*/) Last = cl ;
505 // First = cl au lieu de First = cf
506 else if (Abs(First - cl) < Precision::PConfusion() /*preci*/) First = cf;
508 // on se trouve dans un cas ou l origine est traversee
509 // illegal sur une courbe fermee non periodique
510 // on inverse quand meme les parametres !!!!!!
512 //:S4136 abv 20 Apr 99: r0701_ug.stp #6230: add check in 3d
513 if ( theCurve->Value(First).Distance(theCurve->Value(cf)) < preci ) First = cf;
514 if ( theCurve->Value(Last).Distance(theCurve->Value(cl)) < preci ) Last = cl;
515 if ( First > Last ) {
517 cout << "Warning : parameter range of edge crossing non periodic curve origin" << endl;
519 Standard_Real tmp = First;
525 // The curve is closed within the 3D tolerance
526 else if (theCurve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
527 Handle(Geom_BSplineCurve) aBSpline =
528 Handle(Geom_BSplineCurve)::DownCast(theCurve);
529 if (aBSpline->StartPoint().Distance(aBSpline->EndPoint()) <= preci ) {
530 //:S4136 <= BRepAPI::Precision()) {
531 // l'un des points projecte se trouve sur l'origine du parametrage
532 // de la courbe 3D. L algo a donne cl +- preci au lieu de cf ou vice-versa
533 // DANGER precision 3d applique a une espace 1d
535 // Last = cf au lieu de Last = cl
536 if (Abs(Last - cf) < Precision::PConfusion() /*preci*/) Last = cl ;
537 // First = cl au lieu de First = cf
538 else if (Abs(First - cl) < Precision::PConfusion() /*preci*/) First = cf;
540 // on se trouve dans un cas ou l origine est traversee
541 // illegal sur une courbe fermee non periodique
542 // on inverse quand meme les parametres !!!!!!
545 cout << "Warning : parameter range of edge crossing non periodic curve origin" << endl;
547 Standard_Real tmp = First;
552 //abv 15.03.00 #72 bm1_pe_t4 protection of exceptions in draw
553 else if ( First > Last ) {
555 cout << "Warning: parameter range is bad; curve reversed" << endl;
557 First = theCurve->ReversedParameter ( First );
558 Last = theCurve->ReversedParameter ( Last );
561 //:j9 abv 11 Dec 98: PRO7747 #4875, after :j8: else
562 if (First == Last) { //gka 10.07.1998 file PRO7656 entity 33334
563 First = cf; Last = cl;
564 return Standard_False;
569 cout << "UpdateParam3d Failed" << endl;
570 cout << " - Curve Type : " << theCurve->DynamicType() << endl;
571 cout << " - Param 1 : " << First << endl;
572 cout << " - Param 2 : " << Last << endl;
574 //abv 15.03.00 #72 bm1_pe_t4 protection of exceptions in draw
575 if ( First > Last ) {
577 cout << "Warning: parameter range is bad; curve reversed" << endl;
579 First = theCurve->ReversedParameter ( First );
580 Last = theCurve->ReversedParameter ( Last );
583 //pdn 11.01.99 #144 bm1_pe_t4 protection of exceptions in draw
585 First -= Precision::PConfusion();
586 Last += Precision::PConfusion();
588 return Standard_False;
590 return Standard_True;
593 //=======================================================================
594 //function : FillBndBox
595 //purpose : WORK-AROUND for methods brom BndLib which give not exact bounds
596 //=======================================================================
598 // search for extremum using Newton
599 static Standard_Integer SearchForExtremum (const Handle(Geom2d_Curve)& C2d,
600 const Standard_Real First,
601 const Standard_Real Last,
606 Standard_Real prevpar;
607 for ( Standard_Integer i=0; i <10; i++ ) {
611 C2d->D2 ( par, res, D1, D2 );
612 Standard_Real Det = ( D2 * dir );
613 if ( Abs ( Det ) < 1e-10 ) return Standard_True;
615 par -= ( D1 * dir ) / Det;
616 if ( Abs ( par - prevpar ) < Precision::PConfusion() ) return Standard_True;
618 if ( First - par >= Precision::PConfusion() ||
619 par - Last >= Precision::PConfusion() ) return Standard_False;
621 return Standard_True;
624 void ShapeAnalysis_Curve::FillBndBox (const Handle(Geom2d_Curve)& C2d,
625 const Standard_Real First,
626 const Standard_Real Last,
627 const Standard_Integer NPoints,
628 const Standard_Boolean Exact,
629 Bnd_Box2d &Box) const
631 Standard_Integer nseg = ( NPoints <2 ? 1 : NPoints-1 );
632 Standard_Real step = ( Last - First ) / nseg;
633 for ( Standard_Integer i=0; i <= nseg; i++ ) {
634 Standard_Real par = First + i * step;
635 gp_Pnt2d pnt = C2d->Value ( par );
637 if ( ! Exact ) continue;
640 Standard_Real parextr = par;
641 if ( SearchForExtremum ( C2d, Max(First,par-2.*step), Min(Last,par+2.*step),
642 gp_Vec2d(1,0), parextr, pextr ) ) {
646 if ( SearchForExtremum ( C2d, Max(First,par-2.*step), Min(Last,par+2.*step),
647 gp_Vec2d(0,1), parextr, pextr ) ) {
653 //=======================================================================
654 //function : SelectForwardSeam
656 //=======================================================================
658 Standard_Integer ShapeAnalysis_Curve::SelectForwardSeam(const Handle(Geom2d_Curve)& C1,
659 const Handle(Geom2d_Curve)& C2) const
661 // SelectForward est destine a devenir un outil distinct
662 // Il est sans doute optimisable !
664 Standard_Integer theCurveIndice = 0;
666 Handle(Geom2d_Line) L1 = Handle(Geom2d_Line)::DownCast(C1);
668 // if we have BoundedCurve, create a line from C1
669 Handle(Geom2d_BoundedCurve) BC1 = Handle(Geom2d_BoundedCurve)::DownCast(C1);
670 if (BC1.IsNull()) return theCurveIndice;
671 gp_Pnt2d StartBC1 = BC1->StartPoint();
672 gp_Pnt2d EndBC1 = BC1->EndPoint();
673 gp_Vec2d VecBC1(StartBC1, EndBC1);
674 L1 = new Geom2d_Line(StartBC1, VecBC1);
677 Handle(Geom2d_Line) L2 = Handle(Geom2d_Line)::DownCast(C2);
679 // if we have BoundedCurve, creates a line from C2
680 Handle(Geom2d_BoundedCurve) BC2 = Handle(Geom2d_BoundedCurve)::DownCast(C2);
681 if (BC2.IsNull()) return theCurveIndice;
682 gp_Pnt2d StartBC2 = BC2->StartPoint();
683 gp_Pnt2d EndBC2 = BC2->EndPoint();
684 gp_Vec2d VecBC2(StartBC2, EndBC2);
685 L2 = new Geom2d_Line(StartBC2, VecBC2);
688 Standard_Boolean UdirPos, UdirNeg, VdirPos, VdirNeg;
689 UdirPos = UdirNeg = VdirPos = VdirNeg = Standard_False;
691 gp_Dir2d theDir = L1->Direction();
692 gp_Pnt2d theLoc1 = L1->Location();
693 gp_Pnt2d theLoc2 = L2->Location();
695 if (theDir.X() > 0.) {
696 UdirPos = Standard_True; //szv#4:S4163:12Mar99 Udir unused
697 } else if (theDir.X() < 0.) {
698 UdirNeg = Standard_True; //szv#4:S4163:12Mar99 Udir unused
699 } else if (theDir.Y() > 0.) {
700 VdirPos = Standard_True; //szv#4:S4163:12Mar99 Vdir unused
701 } else if (theDir.Y() < 0.) {
702 VdirNeg = Standard_True; //szv#4:S4163:12Mar99 Vdir unused
706 // max of Loc1.X() Loc2.X()
707 if (theLoc1.X() > theLoc2.X()) theCurveIndice = 1;
708 else theCurveIndice = 2;
709 } else if (VdirNeg) {
710 if (theLoc1.X() > theLoc2.X()) theCurveIndice = 2;
711 else theCurveIndice = 1;
712 } else if (UdirPos) {
713 // min of Loc1.X() Loc2.X()
714 if (theLoc1.Y() < theLoc2.Y()) theCurveIndice = 1;
715 else theCurveIndice = 2;
716 } else if (UdirNeg) {
717 if (theLoc1.Y() < theLoc2.Y()) theCurveIndice = 2;
718 else theCurveIndice = 1;
721 return theCurveIndice;
725 //=============================================================================
726 // Static methods for IsPlanar
728 //=============================================================================
730 static gp_XYZ GetAnyNormal ( gp_XYZ orig )
733 if ( Abs ( orig.Z() ) < Precision::Confusion() )
734 Norm.SetCoord ( 0, 0, 1 );
736 Norm.SetCoord ( orig.Z(), 0, -orig.X() );
737 Standard_Real nrm = Norm.Modulus();
738 if ( nrm < Precision::Confusion() ) Norm.SetCoord ( 0, 0, 1 );
739 else Norm = Norm / nrm;
744 //=======================================================================
745 //function : GetSamplePoints
747 //=======================================================================
748 static void AppendControlPoles (TColgp_SequenceOfPnt& seq,
749 const Handle(Geom_Curve) curve)
751 if ( curve->IsKind(STANDARD_TYPE(Geom_Line))) {
752 seq.Append(curve->Value(0));
753 seq.Append(curve->Value(1));
754 } else if ( curve->IsKind(STANDARD_TYPE(Geom_Conic))) {
755 seq.Append(curve->Value(0));
756 seq.Append(curve->Value(M_PI/2));
757 seq.Append(curve->Value(M_PI));
758 } else if ( curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
759 //DeclareAndCast(Geom_TrimmedCurve, Trimmed, curve);
760 Handle(Geom_TrimmedCurve) Trimmed = *((Handle(Geom_TrimmedCurve) *) &curve);
761 // AppendControlPoles(seq,Trimmed->BasisCurve());
762 Handle(Geom_Curve) aBaseCrv = Trimmed->BasisCurve();
763 Standard_Boolean done = Standard_False;
764 if ( aBaseCrv->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
767 Handle(Geom_Geometry) Ctmp = aBaseCrv->Copy();
768 Handle(Geom_BSplineCurve) bslp = Handle(Geom_BSplineCurve)::DownCast(Ctmp);
769 bslp->Segment(curve->FirstParameter(), curve->LastParameter());
770 AppendControlPoles(seq,bslp);
771 done = Standard_True;
773 catch (Standard_Failure) {
776 else if ( aBaseCrv->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
779 Handle(Geom_Geometry) Ctmp = aBaseCrv->Copy();
780 Handle(Geom_BezierCurve) bz = Handle(Geom_BezierCurve)::DownCast(Ctmp);
781 bz->Segment(curve->FirstParameter(), curve->LastParameter());
782 AppendControlPoles(seq,bz);
783 done = Standard_True;
785 catch (Standard_Failure) {
789 seq.Append(curve->Value(curve->FirstParameter()));
790 seq.Append(curve->Value((curve->FirstParameter() + curve->LastParameter())/2.));
791 seq.Append(curve->Value(curve->LastParameter()));
793 } else if ( curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
794 //DeclareAndCast(Geom_OffsetCurve, OffsetC, curve);
795 Handle(Geom_OffsetCurve) OffsetC = *((Handle(Geom_OffsetCurve) *) &curve);
796 // AppendControlPoles(seq,OffsetC->BasisCurve());
797 seq.Append(curve->Value(curve->FirstParameter()));
798 seq.Append(curve->Value((curve->FirstParameter() + curve->LastParameter())/2.));
799 seq.Append(curve->Value(curve->LastParameter()));
800 } else if ( curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
801 //DeclareAndCast(Geom_BSplineCurve, BSpline, curve);
802 Handle(Geom_BSplineCurve) BSpline = *((Handle(Geom_BSplineCurve) *) &curve);
803 TColgp_Array1OfPnt Poles(1,BSpline->NbPoles());
804 BSpline->Poles(Poles);
805 for(Standard_Integer i = 1; i <= BSpline->NbPoles(); i++)
806 seq.Append(Poles(i));
807 } else if ( curve->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
808 //DeclareAndCast(Geom_BezierCurve, Bezier, curve);
809 //Handle(Geom_BezierCurve) Bezier = Handle(Geom_BezierCurve)::DownCast(curve);
810 Handle(Geom_BezierCurve) Bezier = *((Handle(Geom_BezierCurve) *) &curve);
811 TColgp_Array1OfPnt Poles(1,Bezier->NbPoles());
812 Bezier->Poles(Poles);
813 for(Standard_Integer i = 1; i <= Bezier->NbPoles(); i++)
814 seq.Append(Poles(i));
820 //=======================================================================
821 //function : IsPlanar
822 //purpose : Detects if points lie in some plane and returns normal
823 //=======================================================================
825 Standard_Boolean ShapeAnalysis_Curve::IsPlanar (const TColgp_Array1OfPnt& pnts,
827 const Standard_Real preci)
829 Standard_Real precision = (preci > 0.0)? preci : Precision::Confusion();
830 Standard_Boolean noNorm = (Normal.SquareModulus() == 0);
832 if (pnts.Length() < 3) {
833 gp_XYZ N1 = pnts(1).XYZ()-pnts(2).XYZ();
835 Normal = GetAnyNormal(N1);
836 return Standard_True;
838 return Abs(N1*Normal) < Precision::Confusion();
843 //define a center point
844 gp_XYZ aCenter(0,0,0);
845 Standard_Integer i = 1;
846 for (; i <= pnts.Length(); i++)
847 aCenter += pnts(i).XYZ();
848 aCenter/=pnts.Length();
851 aMaxDir = pnts(1).XYZ() - aCenter;
852 Normal = (pnts(pnts.Length()).XYZ() - aCenter) ^ aMaxDir;
854 for ( i = 1; i < pnts.Length(); i++) {
855 gp_XYZ aTmpDir = pnts(i+1).XYZ() - aCenter;
856 if(aTmpDir.SquareModulus() > aMaxDir.SquareModulus())
859 gp_XYZ aDelta = (pnts(i).XYZ() - aCenter) ^ (pnts(i+1).XYZ() - aCenter);
860 if(Normal*aDelta < 0)
866 // check if points are linear
867 Standard_Real nrm = Normal.Modulus();
868 if ( nrm < Precision::Confusion() ) {
869 Normal = GetAnyNormal(aMaxDir);
870 return Standard_True;
872 Normal = Normal / nrm;
874 Standard_Real mind = RealLast(), maxd = -RealLast(), dev;
875 for (Standard_Integer i = 1; i <= pnts.Length(); i++) {
876 dev = pnts(i).XYZ() * Normal;
877 if (dev < mind) mind = dev;
878 if (dev > maxd) maxd = dev;
881 return ((maxd - mind) <= precision);
885 //=======================================================================
886 //function : IsPlanar
888 //=======================================================================
890 Standard_Boolean ShapeAnalysis_Curve::IsPlanar (const Handle(Geom_Curve)& curve,
892 const Standard_Real preci)
894 Standard_Real precision = (preci > 0.0)? preci : Precision::Confusion();
895 Standard_Boolean noNorm = (Normal.SquareModulus() == 0);
897 if (curve->IsKind(STANDARD_TYPE(Geom_Line))) {
898 //DeclareAndCast(Geom_Line, Line, curve);
899 Handle(Geom_Line) Line = *((Handle(Geom_Line) *) &curve);
900 gp_XYZ N1 = Line->Position().Direction().XYZ();
902 Normal = GetAnyNormal(N1);
903 return Standard_True;
905 return Abs(N1*Normal) < Precision::Confusion();
908 if (curve->IsKind(STANDARD_TYPE(Geom_Conic))) {
909 //DeclareAndCast(Geom_Conic, Conic, curve);
910 Handle(Geom_Conic) Conic = *((Handle(Geom_Conic) *) &curve);
911 gp_XYZ N1 = Conic->Axis().Direction().XYZ();
914 return Standard_True;
916 gp_XYZ aVecMul = N1^Normal;
917 return aVecMul.SquareModulus() < Precision::SquareConfusion();
920 if (curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
921 //DeclareAndCast(Geom_TrimmedCurve, Trimmed, curve);
922 Handle(Geom_TrimmedCurve) Trimmed = *((Handle(Geom_TrimmedCurve) *) &curve);
923 return IsPlanar(Trimmed->BasisCurve(),Normal,precision);
926 if (curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
927 //DeclareAndCast(Geom_OffsetCurve, OffsetC, curve);
928 Handle(Geom_OffsetCurve) OffsetC = *((Handle(Geom_OffsetCurve) *) &curve);
929 return IsPlanar(OffsetC->BasisCurve(),Normal,precision);
932 if (curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
933 //DeclareAndCast(Geom_BSplineCurve, BSpline, curve);
934 Handle(Geom_BSplineCurve) BSpline = *((Handle(Geom_BSplineCurve) *) &curve);
935 TColgp_Array1OfPnt Poles(1,BSpline->NbPoles());
936 BSpline->Poles(Poles);
937 return IsPlanar(Poles,Normal,precision);
940 if (curve->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
941 //DeclareAndCast(Geom_BezierCurve, Bezier, curve);
942 Handle(Geom_BezierCurve) Bezier = *((Handle(Geom_BezierCurve) *) &curve);
943 TColgp_Array1OfPnt Poles(1,Bezier->NbPoles());
944 Bezier->Poles(Poles);
945 return IsPlanar(Poles,Normal,precision);
948 if (curve->IsKind(STANDARD_TYPE(ShapeExtend_ComplexCurve))) {
949 //DeclareAndCast(ShapeExtend_ComplexCurve, Complex, curve);
950 Handle(ShapeExtend_ComplexCurve) Complex = *((Handle(ShapeExtend_ComplexCurve) *) &curve);
951 TColgp_SequenceOfPnt sequence;
952 Standard_Integer i; // svv Jan11 2000 : porting on DEC
953 for (i = 1; i <= Complex->NbCurves(); i++)
954 AppendControlPoles(sequence,Complex->Curve(i));
955 TColgp_Array1OfPnt Poles(1,sequence.Length());
956 for (i=1; i <= sequence.Length(); i++) Poles(i) = sequence(i);
957 return IsPlanar(Poles,Normal,precision);
960 return Standard_False;
963 //=======================================================================
964 //function : GetSamplePoints
966 //=======================================================================
968 Standard_Boolean ShapeAnalysis_Curve::GetSamplePoints (const Handle(Geom_Curve)& curve,
969 const Standard_Real first,
970 const Standard_Real last,
971 TColgp_SequenceOfPnt& seq)
973 Standard_Real adelta = curve->LastParameter() - curve->FirstParameter();
975 return Standard_False;
977 Standard_Integer aK = (Standard_Integer)ceil ((last - first) / adelta);
978 Standard_Integer nbp =100*aK;
979 if(curve->IsKind(STANDARD_TYPE(Geom_Line)))
981 else if(curve->IsKind(STANDARD_TYPE(Geom_Circle)))
984 else if (curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
985 Handle(Geom_BSplineCurve) aBspl = Handle(Geom_BSplineCurve)::DownCast(curve);
987 nbp = aBspl->NbKnots() * aBspl->Degree()*aK;
990 else if (curve->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
991 Handle(Geom_BezierCurve) aB = Handle(Geom_BezierCurve)::DownCast(curve);
992 nbp = 3 + aB->NbPoles();
994 else if(curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
995 Handle(Geom_OffsetCurve) aC = Handle(Geom_OffsetCurve)::DownCast(curve);
996 return GetSamplePoints(aC->BasisCurve(),first,last,seq);
998 else if(curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
999 Handle(Geom_TrimmedCurve) aC = Handle(Geom_TrimmedCurve)::DownCast(curve);
1000 return GetSamplePoints(aC->BasisCurve(),first,last,seq);
1002 Standard_Real step = ( last - first ) / (Standard_Real)( nbp - 1 );
1003 Standard_Real par = first, stop = last - 0.5 * step;
1004 for ( ; par < stop; par += step )
1005 seq.Append(curve->Value(par));
1006 seq.Append(curve->Value(last));
1007 return Standard_True;
1009 //=======================================================================
1010 //function : GetSamplePoints
1012 //=======================================================================
1014 Standard_Boolean ShapeAnalysis_Curve::GetSamplePoints (const Handle(Geom2d_Curve)& curve,
1015 const Standard_Real first,
1016 const Standard_Real last,
1017 TColgp_SequenceOfPnt2d& seq)
1019 //:abv 05.06.02: TUBE.stp
1020 // Use the same distribution of points as BRepTopAdaptor_FClass2d for consistency
1021 Geom2dAdaptor_Curve C ( curve, first, last );
1022 Standard_Integer nbs = Geom2dInt_Geom2dCurveTool::NbSamples(C);
1023 //-- Attention aux bsplines rationnelles de degree 3. (bouts de cercles entre autres)
1024 if (nbs > 2) nbs*=4;
1025 Standard_Real step = ( last - first ) / (Standard_Real)( nbs - 1 );
1026 Standard_Real par = first, stop = last - 0.5 * step;
1027 for ( ; par < stop; par += step )
1028 seq.Append(curve->Value(par));
1029 seq.Append(curve->Value(last));
1030 return Standard_True;
1035 if ( curve->IsKind(STANDARD_TYPE(Geom2d_Line))) {
1036 seq.Append(curve->Value(first));
1037 seq.Append(curve->Value(last));
1038 return Standard_True;
1040 else if(curve->IsKind(STANDARD_TYPE(Geom2d_Conic))) {
1041 step = Min ( M_PI, last-first ) / 19; //:abv 05.06.02 TUBE.stp #19209...: M_PI/16
1042 // if( step>(last-first) ) {
1043 // seq.Append(curve->Value(first));
1044 // seq.Append(curve->Value((last+first)/2));
1045 // seq.Append(curve->Value(last));
1046 // return Standard_True;
1049 Standard_Real par=first;
1050 for(i=0; par<last; i++) {
1051 seq.Append(curve->Value(par));
1054 seq.Append(curve->Value(last));
1055 return Standard_True;
1058 else if ( curve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) {
1059 DeclareAndCast(Geom2d_TrimmedCurve, Trimmed, curve);
1060 return GetControlPoints(Trimmed->BasisCurve(), seq, first, last);
1062 else if ( curve->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) {
1063 DeclareAndCast(Geom2d_BSplineCurve, aBs, curve);
1064 TColStd_SequenceOfReal aSeqParam;
1066 aSeqParam.Append(first);
1067 for(i=1; i<=aBs->NbKnots(); i++) {
1068 if( aBs->Knot(i)>first && aBs->Knot(i)<last )
1069 aSeqParam.Append(aBs->Knot(i));
1071 aSeqParam.Append(last);
1072 Standard_Integer NbPoints=aBs->Degree();
1073 if( (aSeqParam.Length()-1)*NbPoints>10 ) {
1074 for(i=1; i<aSeqParam.Length(); i++) {
1075 Standard_Real FirstPar = aSeqParam.Value(i);
1076 Standard_Real LastPar = aSeqParam.Value(i+1);
1077 step = (LastPar-FirstPar)/NbPoints;
1078 for(Standard_Integer k=0; k<NbPoints; k++ ) {
1079 aBs->D0(FirstPar+step*k, Ptmp);
1083 aBs->D0(last, Ptmp);
1085 return Standard_True;
1088 step = (last-first)/10;
1089 for(Standard_Integer k=0; k<=10; k++ ) {
1090 aBs->D0(first+step*k, Ptmp);
1093 return Standard_True;
1097 else if ( curve->IsKind(STANDARD_TYPE(Geom2d_BezierCurve))) {
1098 DeclareAndCast(Geom2d_BezierCurve, aBz, curve);
1100 Standard_Integer NbPoints=aBz->Degree();
1101 step = (last-first)/NbPoints;
1102 for(Standard_Integer k=0; k<NbPoints; k++ ) {
1103 aBz->D0(first+step*k, Ptmp);
1106 aBz->D0(last, Ptmp);
1108 return Standard_True;
1111 return Standard_False;
1115 //=======================================================================
1116 //function : IsClosed
1118 //=======================================================================
1120 Standard_Boolean ShapeAnalysis_Curve::IsClosed(const Handle(Geom_Curve)& theCurve,
1121 const Standard_Real preci)
1123 if (theCurve->IsClosed())
1124 return Standard_True;
1126 Standard_Real prec = Max (preci, Precision::Confusion());
1129 f = theCurve->FirstParameter();
1130 l = theCurve->LastParameter();
1132 if (Precision::IsInfinite (f) || Precision::IsInfinite (l))
1133 return Standard_False;
1135 Standard_Real aClosedVal = theCurve->Value(f).SquareDistance(theCurve->Value(l));
1136 Standard_Real preci2 = prec*prec;
1138 return (aClosedVal <= preci2);
1140 //=======================================================================
1141 //function : IsPeriodic
1143 //=======================================================================
1145 Standard_Boolean ShapeAnalysis_Curve::IsPeriodic(const Handle(Geom_Curve)& theCurve)
1147 // 15.11.2002 PTV OCC966
1148 // remove regressions in DE tests (diva, divb, divc, toe3) in KAS:dev
1149 // ask IsPeriodic on BasisCurve
1150 Handle(Geom_Curve) aTmpCurve = theCurve;
1151 while ( (aTmpCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) ||
1152 (aTmpCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) ) {
1153 if (aTmpCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
1154 aTmpCurve = Handle(Geom_OffsetCurve)::DownCast(aTmpCurve)->BasisCurve();
1155 if (aTmpCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
1156 aTmpCurve = Handle(Geom_TrimmedCurve)::DownCast(aTmpCurve)->BasisCurve();
1158 return aTmpCurve->IsPeriodic();
1161 Standard_Boolean ShapeAnalysis_Curve::IsPeriodic(const Handle(Geom2d_Curve)& theCurve)
1163 // 15.11.2002 PTV OCC966
1164 // remove regressions in DE tests (diva, divb, divc, toe3) in KAS:dev
1165 // ask IsPeriodic on BasisCurve
1166 Handle(Geom2d_Curve) aTmpCurve = theCurve;
1167 while ( (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve))) ||
1168 (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) ) {
1169 if (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
1170 aTmpCurve = Handle(Geom2d_OffsetCurve)::DownCast(aTmpCurve)->BasisCurve();
1171 if (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
1172 aTmpCurve = Handle(Geom2d_TrimmedCurve)::DownCast(aTmpCurve)->BasisCurve();
1174 return aTmpCurve->IsPeriodic();