0027352: Optimal axis-aligned bounding box for a shape
[occt.git] / src / BndLib / BndLib_Add2dCurve.cxx
CommitLineData
b311480e 1// Copyright (c) 1996-1999 Matra Datavision
973c2be1 2// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 3//
973c2be1 4// This file is part of Open CASCADE Technology software library.
b311480e 5//
d5f74e42 6// This library is free software; you can redistribute it and/or modify it under
7// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 8// by the Free Software Foundation, with special exception defined in the file
9// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10// distribution for complete text of the license and disclaimer of any warranty.
b311480e 11//
973c2be1 12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
7fd59977 14
7fd59977 15
42cf5bc1 16#include <Adaptor2d_Curve2d.hxx>
17#include <Bnd_Box2d.hxx>
18#include <BndLib_Add2dCurve.hxx>
19#include <Geom2d_BezierCurve.hxx>
20#include <Geom2d_BSplineCurve.hxx>
59495dbe 21#include <Geom2d_Circle.hxx>
42cf5bc1 22#include <Geom2d_Conic.hxx>
23#include <Geom2d_Curve.hxx>
59495dbe 24#include <Geom2d_Ellipse.hxx>
42cf5bc1 25#include <Geom2d_Geometry.hxx>
59495dbe 26#include <Geom2d_Hyperbola.hxx>
59495dbe 27#include <Geom2d_Line.hxx>
42cf5bc1 28#include <Geom2d_OffsetCurve.hxx>
29#include <Geom2d_Parabola.hxx>
30#include <Geom2d_TrimmedCurve.hxx>
59495dbe 31#include <Geom2dAdaptor_Curve.hxx>
42cf5bc1 32#include <gp.hxx>
33#include <Precision.hxx>
34#include <Standard_Type.hxx>
3ba87fdb 35#include <math_MultipleVarFunction.hxx>
36#include <math_Function.hxx>
37#include <math_BrentMinimum.hxx>
38#include <math_PSO.hxx>
7fd59977 39
40//=======================================================================
59495dbe 41//function : BndLib_Box2dCurve
7fd59977 42//purpose :
43//=======================================================================
59495dbe 44class BndLib_Box2dCurve {
45 public:
46 BndLib_Box2dCurve();
47
48 virtual ~BndLib_Box2dCurve();
49
50 void SetCurve(const Handle(Geom2d_Curve)& aC);
51
35c0599a 52 const Handle(Geom2d_Curve)& Curve() const;
59495dbe 53
54 void SetRange(const Standard_Real aT1,
55 const Standard_Real aT2);
56
57 void Range(Standard_Real& aT1,
58 Standard_Real& aT2) const;
59
60 const Bnd_Box2d& Box() const;
7fd59977 61
59495dbe 62 void Perform();
63
3ba87fdb 64 void PerformOptimal(const Standard_Real Tol);
65
59495dbe 66 void Clear();
67
68 Standard_Integer ErrorStatus() const;
69 //
70 //-----------------------------
71 protected:
72 void CheckData();
73 void GetInfoBase();
74 void PerformLineConic();
75 void PerformBezier();
76 void PerformBSpline();
77 void PerformOther();
78 void D0(const Standard_Real, gp_Pnt2d&);
79 //
80 void Compute(const Handle(Geom2d_Conic)&,
81 const GeomAbs_CurveType,
82 const Standard_Real,
83 const Standard_Real,
84 Bnd_Box2d& aBox2D);
85 //
86 static
87 Standard_Integer Compute(const Handle(Geom2d_Conic)&,
88 const GeomAbs_CurveType,
89 Standard_Real *);
90 static
91 Standard_Boolean IsTypeBase(const Handle(Geom2d_Curve)& ,
92 GeomAbs_CurveType& );
93 static
94 Standard_Real AdjustToPeriod(const Standard_Real ,
95 const Standard_Real );
96 //
97 void PerformOnePoint();
3ba87fdb 98 //
99 void PerformGenCurv(const Standard_Real Tol = Precision::PConfusion());
100 //
101 Standard_Integer NbSamples();
102 //
103 Standard_Real AdjustExtr(const Standard_Real UMin,
104 const Standard_Real UMax,
105 const Standard_Real Extr0,
106 const Standard_Integer CoordIndx,
107 const Standard_Real Tol,
108 const Standard_Boolean IsMin);
59495dbe 109 //-----------------------------
110 protected:
35c0599a 111 Handle(Geom2d_Curve) myCurve;
59495dbe 112 Bnd_Box2d myBox;
113 Standard_Integer myErrorStatus;
35c0599a 114 Handle(Geom2d_Curve) myCurveBase;
59495dbe 115 Standard_Real myOffsetBase;
116 Standard_Boolean myOffsetFlag;
117 Standard_Real myT1;
118 Standard_Real myT2;
119 GeomAbs_CurveType myTypeBase;
120};
3ba87fdb 121//
122class Curv2dMaxMinCoordMVar : public math_MultipleVarFunction
123{
124public:
125 Curv2dMaxMinCoordMVar(const Handle(Geom2d_Curve)& theCurve,
126 const Standard_Real UMin,
127 const Standard_Real UMax,
128 const Standard_Integer CoordIndx,
129 const Standard_Real Sign)
130: myCurve(theCurve),
131 myUMin(UMin),
132 myUMax(UMax),
133 myCoordIndx(CoordIndx),
134 mySign(Sign)
135 {
136 }
137
138 Standard_Boolean Value (const math_Vector& X,
139 Standard_Real& F)
140 {
141 if (!CheckInputData(X(1)))
142 {
143 return Standard_False;
144 }
145 gp_Pnt2d aP = myCurve->Value(X(1));
146
147 F = mySign * aP.Coord(myCoordIndx);
148
149 return Standard_True;
150 }
151
152
153
154 Standard_Integer NbVariables() const
155 {
156 return 1;
157 }
158
159private:
160 Curv2dMaxMinCoordMVar & operator = (const Curv2dMaxMinCoordMVar & theOther);
161
162 Standard_Boolean CheckInputData(Standard_Real theParam)
163 {
164 if (theParam < myUMin ||
165 theParam > myUMax)
166 return Standard_False;
167 return Standard_True;
168 }
169
170 const Handle(Geom2d_Curve)& myCurve;
171 Standard_Real myUMin;
172 Standard_Real myUMax;
173 Standard_Integer myCoordIndx;
174 Standard_Real mySign;
175};
176//
177class Curv2dMaxMinCoord : public math_Function
178{
179public:
180 Curv2dMaxMinCoord(const Handle(Geom2d_Curve)& theCurve,
181 const Standard_Real UMin,
182 const Standard_Real UMax,
183 const Standard_Integer CoordIndx,
184 const Standard_Real Sign)
185: myCurve(theCurve),
186 myUMin(UMin),
187 myUMax(UMax),
188 myCoordIndx(CoordIndx),
189 mySign(Sign)
190 {
191 }
192
193 Standard_Boolean Value (const Standard_Real X,
194 Standard_Real& F)
195 {
196 if (!CheckInputData(X))
197 {
198 return Standard_False;
199 }
200 gp_Pnt2d aP = myCurve->Value(X);
201
202 F = mySign * aP.Coord(myCoordIndx);
203
204 return Standard_True;
205 }
59495dbe 206
3ba87fdb 207private:
208 Curv2dMaxMinCoord & operator = (const Curv2dMaxMinCoord & theOther);
209
210 Standard_Boolean CheckInputData(Standard_Real theParam)
211 {
212 if (theParam < myUMin ||
213 theParam > myUMax)
214 return Standard_False;
215 return Standard_True;
216 }
217
218 const Handle(Geom2d_Curve)& myCurve;
219 Standard_Real myUMin;
220 Standard_Real myUMax;
221 Standard_Integer myCoordIndx;
222 Standard_Real mySign;
223};
59495dbe 224
225//=======================================================================
226//function :
227//purpose :
228//=======================================================================
229BndLib_Box2dCurve::BndLib_Box2dCurve()
7fd59977 230{
59495dbe 231 Clear();
7fd59977 232}
7fd59977 233//=======================================================================
59495dbe 234//function : ~
7fd59977 235//purpose :
236//=======================================================================
59495dbe 237BndLib_Box2dCurve::~BndLib_Box2dCurve()
238{
239}
240//=======================================================================
241//function : Clear
242//purpose :
243//=======================================================================
244void BndLib_Box2dCurve::Clear()
245{
246 myBox.SetVoid();
247 //
248 myErrorStatus=-1;
249 myTypeBase=GeomAbs_OtherCurve;
250 myOffsetBase=0.;
251 myOffsetFlag=Standard_False;
252}
253//=======================================================================
254//function : SetCurve
255//purpose :
256//=======================================================================
257void BndLib_Box2dCurve::SetCurve(const Handle(Geom2d_Curve)& aC2D)
258{
259 myCurve=aC2D;
260}
261//=======================================================================
262//function : Curve
263//purpose :
264//=======================================================================
265const Handle(Geom2d_Curve)& BndLib_Box2dCurve::Curve()const
266{
267 return myCurve;
268}
269//=======================================================================
270//function : SetRange
271//purpose :
272//=======================================================================
273void BndLib_Box2dCurve::SetRange(const Standard_Real aT1,
274 const Standard_Real aT2)
275{
276 myT1=aT1;
277 myT2=aT2;
278}
279//=======================================================================
280//function : tRange
281//purpose :
282//=======================================================================
283void BndLib_Box2dCurve::Range(Standard_Real& aT1,
284 Standard_Real& aT2) const
285{
286 aT1=myT1;
287 aT2=myT2;
288}
289//=======================================================================
290//function : ErrorStatus
291//purpose :
292//=======================================================================
293Standard_Integer BndLib_Box2dCurve::ErrorStatus()const
294{
295 return myErrorStatus;
296}
297//=======================================================================
298//function : Box
299//purpose :
300//=======================================================================
301const Bnd_Box2d& BndLib_Box2dCurve::Box()const
302{
303 return myBox;
304}
305//=======================================================================
306//function : CheckData
307//purpose :
308//=======================================================================
309void BndLib_Box2dCurve::CheckData()
310{
311 myErrorStatus=0;
312 //
313 if(myCurve.IsNull()) {
314 myErrorStatus=10;
315 return;
316 }
317 //
318 if(myT1>myT2) {
319 myErrorStatus=12; // invalid range
320 return;
321 }
322}
323//=======================================================================
324//function : Perform
325//purpose :
326//=======================================================================
327void BndLib_Box2dCurve::Perform()
7fd59977 328{
59495dbe 329 Clear();
330 //
331 myErrorStatus=0;
332 //
333 CheckData();
334 if(myErrorStatus) {
335 return;
336 }
337 //
338 if (myT1==myT2) {
339 PerformOnePoint();
340 return;
341 }
342 //
343 GetInfoBase();
344 if(myErrorStatus) {
345 return;
346 }
347 //
348 if (myTypeBase==GeomAbs_Line ||
349 myTypeBase==GeomAbs_Circle ||
350 myTypeBase==GeomAbs_Ellipse ||
351 myTypeBase==GeomAbs_Parabola ||
352 myTypeBase==GeomAbs_Hyperbola) { // LineConic
353 PerformLineConic();
354 }
355 else if (myTypeBase==GeomAbs_BezierCurve) { // Bezier
356 PerformBezier();
357 }
358 else if (myTypeBase==GeomAbs_BSplineCurve) { //B-Spline
359 PerformBSpline();
360 }
361 else {
362 myErrorStatus=11; // unknown type base
363 }
364}
365//=======================================================================
3ba87fdb 366//function : PerformOptimal
367//purpose :
368//=======================================================================
369void BndLib_Box2dCurve::PerformOptimal(const Standard_Real Tol)
370{
371 Clear();
372 myErrorStatus=0;
373 CheckData();
374
375 if(myErrorStatus) {
376 return;
377 }
378
379 if (myT1==myT2) {
380 PerformOnePoint();
381 return;
382 }
383
384 GetInfoBase();
385 if(myErrorStatus) {
386 return;
387 }
388
389 if (myTypeBase==GeomAbs_Line ||
390 myTypeBase==GeomAbs_Circle ||
391 myTypeBase==GeomAbs_Ellipse ||
392 myTypeBase==GeomAbs_Parabola ||
393 myTypeBase==GeomAbs_Hyperbola) { // LineConic
394 PerformLineConic();
395 }
396 else {
397 PerformGenCurv(Tol);
398 }
399}
400//=======================================================================
59495dbe 401//function : PerformOnePoint
402//purpose :
403//=======================================================================
404void BndLib_Box2dCurve::PerformOnePoint()
405{
406 gp_Pnt2d aP2D;
407 //
408 myCurve->D0(myT1, aP2D);
409 myBox.Add(aP2D);
410}
411//=======================================================================
412//function : PerformBezier
413//purpose :
414//=======================================================================
415void BndLib_Box2dCurve::PerformBezier()
416{
417 if (myOffsetFlag) {
418 PerformOther();
419 return;
420 }
421 //
422 Standard_Integer i, aNbPoles;
423 Standard_Real aT1, aT2, aTb[2];
424 gp_Pnt2d aP2D;
425 Handle(Geom2d_Geometry) aG;
426 Handle(Geom2d_BezierCurve) aCBz, aCBzSeg;
427 //
428 myErrorStatus=0;
429 Bnd_Box2d& aBox2D=myBox;
430 //
431 aCBz=Handle(Geom2d_BezierCurve)::DownCast(myCurveBase);
432 aT1=aCBz->FirstParameter();
433 aT2=aCBz->LastParameter();
434 //
435 aTb[0]=myT1;
436 if (aTb[0]<aT1) {
437 aTb[0]=aT1;
438 }
439 //
440 aTb[1]=myT2;
441 if (aTb[1]>aT2) {
442 aTb[1]=aT2;
443 }
444 //
445 if (!(aT1==aTb[0] && aT2==aTb[1])) {
446 aG=aCBz->Copy();
447 //
448 aCBzSeg=Handle(Geom2d_BezierCurve)::DownCast(aG);
449 aCBzSeg->Segment(aTb[0], aTb[1]);
450 aCBz=aCBzSeg;
451 }
452 //
453 aNbPoles=aCBz->NbPoles();
454 for (i=1; i<=aNbPoles; ++i) {
455 aP2D=aCBz->Pole(i);
456 aBox2D.Add(aP2D);
457 }
458}
459//=======================================================================
460//function : PerformBSpline
461//purpose :
462//=======================================================================
463void BndLib_Box2dCurve::PerformBSpline()
464{
465 if (myOffsetFlag) {
466 PerformOther();
467 return;
468 }
469 //
470 Standard_Integer i, aNbPoles;
471 Standard_Real aT1, aT2, aTb[2];
472 gp_Pnt2d aP2D;
473 Handle(Geom2d_Geometry) aG;
474 Handle(Geom2d_BSplineCurve) aCBS, aCBSs;
475 //
476 myErrorStatus=0;
477 Bnd_Box2d& aBox2D=myBox;
478 //
479 aCBS=Handle(Geom2d_BSplineCurve)::DownCast(myCurveBase);
480 aT1=aCBS->FirstParameter();
481 aT2=aCBS->LastParameter();
482 //
483 aTb[0]=myT1;
484 if (aTb[0]<aT1) {
485 aTb[0]=aT1;
486 }
487 aTb[1]=myT2;
488 if (aTb[1]>aT2) {
489 aTb[1]=aT2;
490 }
7fd59977 491
59495dbe 492 if(aTb[1] < aTb[0])
493 {
494 aTb[0]=aT1;
495 aTb[1]=aT2;
496 }
497
498 //
499 if (!(aT1==aTb[0] && aT2==aTb[1])) {
500 aG=aCBS->Copy();
501 //
502 aCBSs=Handle(Geom2d_BSplineCurve)::DownCast(aG);
503 aCBSs->Segment(aTb[0], aTb[1]);
504 aCBS=aCBSs;
505 }
506 //
507 aNbPoles=aCBS->NbPoles();
508 for (i=1; i<=aNbPoles; ++i) {
509 aP2D=aCBS->Pole(i);
510 aBox2D.Add(aP2D);
511 }
512}
513//=======================================================================
514//function : PerformOther
515//purpose :
516//=======================================================================
517void BndLib_Box2dCurve::PerformOther()
518{
519 Standard_Integer j, aNb;
520 Standard_Real aT, dT;
521 gp_Pnt2d aP2D;
522 //
523 aNb=33;
524 dT=(myT2-myT1)/(aNb-1);
525 //
526 aT=myT1;
527 for (j=0; j<aNb; ++j) {
528 aT=j*dT;
529 myCurve->D0(aT, aP2D);
530 myBox.Add(aP2D);
531 }
532 myCurve->D0(myT2, aP2D);
533 myBox.Add(aP2D);
534}
535//=======================================================================
3ba87fdb 536//function : NbSamples
537//purpose :
538//=======================================================================
539Standard_Integer BndLib_Box2dCurve::NbSamples()
540{
541 Standard_Integer N;
542 switch (myTypeBase) {
543 case GeomAbs_BezierCurve:
544 {
545 Handle(Geom2d_BezierCurve) aCBz=Handle(Geom2d_BezierCurve)::DownCast(myCurveBase);
546 N = aCBz->NbPoles();
547 //By default parametric range of Bezier curv is [0, 1]
548 Standard_Real du = myT2 - myT1;
549 if(du < .9)
550 {
551 N = RealToInt(du*N) + 1;
552 N = Max(N, 5);
553 }
554 break;
555 }
556 case GeomAbs_BSplineCurve:
557 {
558 Handle(Geom2d_BSplineCurve) aCBS=Handle(Geom2d_BSplineCurve)::DownCast(myCurveBase);
559 N = (aCBS->Degree() + 1)*(aCBS->NbKnots() -1);
560 Standard_Real umin = aCBS->FirstParameter(),
561 umax = aCBS->LastParameter();
562 Standard_Real du = (myT2 - myT1) / (umax - umin);
563 if(du < .9)
564 {
565 N = RealToInt(du*N) + 1;
566 N = Max(N, 5);
567 }
568 break;
569 }
570 default:
571 N = 17;
572 }
573 return Min (23,N);
574}
575//=======================================================================
576//function : AdjustExtr
577//purpose :
578//=======================================================================
579Standard_Real BndLib_Box2dCurve::AdjustExtr(const Standard_Real UMin,
580 const Standard_Real UMax,
581 const Standard_Real Extr0,
582 const Standard_Integer CoordIndx,
583 const Standard_Real Tol,
584 const Standard_Boolean IsMin)
585{
586 Standard_Real aSign = IsMin ? 1.:-1.;
587 Standard_Real extr = aSign * Extr0;
588 //
589 Standard_Real Du = (myCurve->LastParameter() - myCurve->FirstParameter());
590 //
591 Geom2dAdaptor_Curve aGAC(myCurve);
592 Standard_Real UTol = Max(aGAC.Resolution(Tol), Precision::PConfusion());
593 Standard_Real reltol = UTol / Max(Abs(UMin), Abs(UMax));
594 if(UMax - UMin < 0.01 * Du)
595 {
596 //It is suggested that function has one extremum on small interval
597 math_BrentMinimum anOptLoc(reltol, 100, UTol);
598 Curv2dMaxMinCoord aFunc(myCurve, UMin, UMax, CoordIndx, aSign);
599 anOptLoc.Perform(aFunc, UMin, (UMin+UMax)/2., UMax);
600 if(anOptLoc.IsDone())
601 {
602 extr = anOptLoc.Minimum();
603 return aSign * extr;
604 }
605 }
606 //
607 Standard_Integer aNbParticles = Max(8, RealToInt(32 * (UMax - UMin) / Du));
608 Standard_Real maxstep = (UMax - UMin) / (aNbParticles + 1);
609 math_Vector aT(1,1);
610 math_Vector aLowBorder(1,1);
611 math_Vector aUppBorder(1,1);
612 math_Vector aSteps(1,1);
613 aLowBorder(1) = UMin;
614 aUppBorder(1) = UMax;
615 aSteps(1) = Min(0.1 * Du, maxstep);
616
617 Curv2dMaxMinCoordMVar aFunc(myCurve, UMin, UMax, CoordIndx, aSign);
618 math_PSO aFinder(&aFunc, aLowBorder, aUppBorder, aSteps, aNbParticles);
619 aFinder.Perform(aSteps, extr, aT);
620 //
621 math_BrentMinimum anOptLoc(reltol, 100, UTol);
622 Curv2dMaxMinCoord aFunc1(myCurve, UMin, UMax, CoordIndx, aSign);
623 anOptLoc.Perform(aFunc1, Max(aT(1) - aSteps(1), UMin), aT(1), Min(aT(1) + aSteps(1), UMax));
624
625 if(anOptLoc.IsDone())
626 {
627 extr = anOptLoc.Minimum();
628 return aSign * extr;
629 }
630
631 return aSign * extr;
632}
633
634//=======================================================================
635//function : PerformGenCurv
636//purpose :
637//=======================================================================
638void BndLib_Box2dCurve::PerformGenCurv(const Standard_Real Tol)
639{
640 //
641 Standard_Integer Nu = NbSamples();
642 //
643 Standard_Real CoordMin[2] = {RealLast(), RealLast()};
644 Standard_Real CoordMax[2] = {-RealLast(), -RealLast()};
645 Standard_Real DeflMax[2] = {-RealLast(), -RealLast()};
646 //
647 gp_Pnt2d P;
648 Standard_Integer i, k;
649 Standard_Real du = (myT2 - myT1)/(Nu-1), du2 = du / 2.;
650 NCollection_Array1<gp_XY> aPnts(1, Nu);
651 Standard_Real u;
652 for (i = 1, u = myT1; i <= Nu; i++, u += du)
653 {
654 D0(u,P);
655 aPnts(i) = P.XY();
656 //
657 for(k = 0; k < 2; ++k)
658 {
659 if(CoordMin[k] > P.Coord(k+1))
660 {
661 CoordMin[k] = P.Coord(k+1);
662 }
663 if(CoordMax[k] < P.Coord(k+1))
664 {
665 CoordMax[k] = P.Coord(k+1);
666 }
667 }
668 //
669 if(i > 1)
670 {
671 gp_XY aPm = 0.5 * (aPnts(i-1) + aPnts(i));
672 D0(u - du2, P);
673 gp_XY aD = (P.XY() - aPm);
674 for(k = 0; k < 2; ++k)
675 {
676 if(CoordMin[k] > P.Coord(k+1))
677 {
678 CoordMin[k] = P.Coord(k+1);
679 }
680 if(CoordMax[k] < P.Coord(k+1))
681 {
682 CoordMax[k] = P.Coord(k+1);
683 }
684 Standard_Real d = Abs(aD.Coord(k+1));
685 if(DeflMax[k] < d)
686 {
687 DeflMax[k] = d;
688 }
689 }
690 }
691 }
692 //
693 //Adjusting minmax
694 for(k = 0; k < 2; ++k)
695 {
696 Standard_Real d = DeflMax[k];
697 if(d <= Tol)
698 {
699 continue;
700 }
701 Standard_Real CMin = CoordMin[k];
702 Standard_Real CMax = CoordMax[k];
703 for(i = 1; i <= Nu; ++i)
704 {
705 if(aPnts(i).Coord(k+1) - CMin < d)
706 {
707 Standard_Real tmin, tmax;
708 tmin = myT1 + Max(0, i-2) * du;
709 tmax = myT1 + Min(Nu-1, i) * du;
710 Standard_Real cmin = AdjustExtr(tmin, tmax,
711 CMin, k + 1, Tol, Standard_True);
712 if(cmin < CMin)
713 {
714 CMin = cmin;
715 }
716 }
717 else if(CMax - aPnts(i).Coord(k+1) < d)
718 {
719 Standard_Real tmin, tmax;
720 tmin = myT1 + Max(0, i-2) * du;
721 tmax = myT1 + Min(Nu-1, i) * du;
722 Standard_Real cmax = AdjustExtr(tmin, tmax,
723 CMax, k + 1, Tol, Standard_False);
724 if(cmax > CMax)
725 {
726 CMax = cmax;
727 }
728 }
729 }
730 CoordMin[k] = CMin;
731 CoordMax[k] = CMax;
732 }
733
734 myBox.Add(gp_Pnt2d(CoordMin[0], CoordMin[1]));
735 myBox.Add(gp_Pnt2d(CoordMax[0], CoordMax[1]));
736 myBox.Enlarge(Tol);
737}
738//=======================================================================
59495dbe 739//function : D0
740//purpose :
741//=======================================================================
742void BndLib_Box2dCurve::D0(const Standard_Real aU,
743 gp_Pnt2d& aP2D)
744{
745 gp_Vec2d aV1;
746 //
747 myCurveBase->D1(aU, aP2D, aV1);
748 //
749 if (myOffsetFlag) {
750 Standard_Integer aIndex, aMaxDegree;
751 Standard_Real aA, aB, aR, aRes;
752 //
753 aMaxDegree=9;
754 aIndex = 2;
755 aRes=gp::Resolution();
756 //
757 while (aV1.Magnitude() <= aRes && aIndex <= aMaxDegree) {
758 aV1=myCurveBase->DN(aU, aIndex);
759 ++aIndex;
7fd59977 760 }
59495dbe 761 //
762 aA=aV1.Y();
763 aB=-aV1.X();
764 aR=sqrt(aA*aA+aB*aB);
765 if(aR<=aRes) {
766 myErrorStatus=13;
767 return;
768 }
769 //
770 aR=myOffsetBase/aR;
771 aA=aA*aR;
772 aB=aB*aR;
773 aP2D.SetCoord(aP2D.X()+aA, aP2D.Y()+aB);
774 }
775 //
776}
777//=======================================================================
778//function : GetInfoBase
779//purpose :
780//=======================================================================
781void BndLib_Box2dCurve::GetInfoBase()
782{
783 Standard_Boolean bIsTypeBase;
784 Standard_Integer iTrimmed, iOffset;
785 GeomAbs_CurveType aTypeB;
786 Handle(Geom2d_Curve) aC2DB;
787 Handle(Geom2d_TrimmedCurve) aCT2D;
788 Handle(Geom2d_OffsetCurve) aCF2D;
789 //
790 myErrorStatus=0;
791 myTypeBase=GeomAbs_OtherCurve;
792 myOffsetBase=0;
793 //
794 aC2DB=myCurve;
795 bIsTypeBase=IsTypeBase(aC2DB, aTypeB);
796 if (bIsTypeBase) {
797 myTypeBase=aTypeB;
798 myCurveBase=myCurve;
799 return;
800 }
801 //
802 aC2DB=myCurve;
803 while(!bIsTypeBase) {
804 iTrimmed=0;
805 iOffset=0;
806 aCT2D=Handle(Geom2d_TrimmedCurve)::DownCast(aC2DB);
807 if (!aCT2D.IsNull()) {
808 aC2DB=aCT2D->BasisCurve();
809 ++iTrimmed;
7fd59977 810 }
59495dbe 811 //
812 aCF2D=Handle(Geom2d_OffsetCurve)::DownCast(aC2DB);
813 if (!aCF2D.IsNull()) {
814 Standard_Real aOffset;
815 //
816 aOffset=aCF2D->Offset();
817 myOffsetBase=myOffsetBase+aOffset;
818 myOffsetFlag=Standard_True;
819 //
820 aC2DB=aCF2D->BasisCurve();
821 ++iOffset;
7fd59977 822 }
59495dbe 823 //
824 if (!(iTrimmed || iOffset)) {
7fd59977 825 break;
826 }
59495dbe 827 //
828 bIsTypeBase=IsTypeBase(aC2DB, aTypeB);
829 if (bIsTypeBase) {
830 myTypeBase=aTypeB;
831 myCurveBase=aC2DB;
832 return;
7fd59977 833 }
59495dbe 834 }
835 //
836 myErrorStatus=11; // unknown type base
837}
838//=======================================================================
839//function : IsTypeBase
840//purpose :
841//=======================================================================
842Standard_Boolean BndLib_Box2dCurve::IsTypeBase
843 (const Handle(Geom2d_Curve)& aC2D,
844 GeomAbs_CurveType& aTypeB)
845{
846 Standard_Boolean bRet;
847 Handle(Standard_Type) aType;
848 //
849 bRet=Standard_True;
850 //
851 aType=aC2D->DynamicType();
852 if (aType==STANDARD_TYPE(Geom2d_Line)) {
853 aTypeB=GeomAbs_Line;
854 }
855 else if (aType==STANDARD_TYPE(Geom2d_Circle)) {
856 aTypeB=GeomAbs_Circle;
857 }
858 else if (aType==STANDARD_TYPE(Geom2d_Ellipse)) {
859 aTypeB=GeomAbs_Ellipse;
860 }
861 else if (aType==STANDARD_TYPE(Geom2d_Parabola)) {
862 aTypeB=GeomAbs_Parabola;
863 }
864 else if (aType==STANDARD_TYPE(Geom2d_Hyperbola)) {
865 aTypeB=GeomAbs_Hyperbola;
866 }
867 else if (aType==STANDARD_TYPE(Geom2d_BezierCurve)) {
868 aTypeB=GeomAbs_BezierCurve;
869 }
870 else if (aType==STANDARD_TYPE(Geom2d_BSplineCurve)) {
871 aTypeB=GeomAbs_BSplineCurve;
872 }
873 else {
874 aTypeB=GeomAbs_OtherCurve;
875 bRet=!bRet;
876 }
877 return bRet;
878}
879//=======================================================================
880//function : PerformLineConic
881//purpose :
882//=======================================================================
883void BndLib_Box2dCurve::PerformLineConic()
884{
885 Standard_Integer i, iInf[2];
bcf50875 886 Standard_Real aTb[2];
59495dbe 887 gp_Pnt2d aP2D;
888 //
889 myErrorStatus=0;
890 //
891 Bnd_Box2d& aBox2D=myBox;
892 //
59495dbe 893 iInf[0]=0;
894 iInf[1]=0;
895 aTb[0]=myT1;
896 aTb[1]=myT2;
897 //
898 for (i=0; i<2; ++i) {
899 if (Precision::IsNegativeInfinite(aTb[i])) {
900 D0(aTb[i], aP2D);
901 aBox2D.Add(aP2D);
902 ++iInf[0];
903 }
904 else if (Precision::IsPositiveInfinite(aTb[i])) {
905 D0(aTb[i], aP2D);
906 aBox2D.Add(aP2D);
907 ++iInf[1];
908 }
909 else {
910 D0(aTb[i], aP2D);
911 aBox2D.Add(aP2D);
912 }
913 }
914 //
915 if (myTypeBase==GeomAbs_Line) {
916 return;
917 }
918 //
919 if (iInf[0] && iInf[1]) {
920 return;
921 }
922 //-------------
923 Handle(Geom2d_Conic) aConic2D;
924 //
925 aConic2D=Handle(Geom2d_Conic)::DownCast(myCurveBase);
926 Compute(aConic2D, myTypeBase, aTb[0], aTb[1], aBox2D);
927
928}
929//=======================================================================
930//function : Compute
931//purpose :
932//=======================================================================
933void BndLib_Box2dCurve::Compute(const Handle(Geom2d_Conic)& aConic2D,
934 const GeomAbs_CurveType aType,
935 const Standard_Real aT1,
936 const Standard_Real aT2,
937 Bnd_Box2d& aBox2D)
938{
939 Standard_Integer i, aNbT;
99661617 940 Standard_Real pT[10], aT, aTwoPI, dT, aEps;
59495dbe 941 gp_Pnt2d aP2D;
942 //
943 aNbT=Compute(aConic2D, aType, pT);
944 //
945 if (aType==GeomAbs_Parabola || aType==GeomAbs_Hyperbola) {
946 for (i=0; i<aNbT; ++i) {
947 aT=pT[i];
948 if (aT>aT1 && aT<aT2) {
949 D0(aT, aP2D);
950 aBox2D.Add(aP2D);
7fd59977 951 }
59495dbe 952 }
953 return;
954 }
955 //
956 //aType==GeomAbs_Circle || aType==GeomAbs_Ellipse
957 aEps=1.e-14;
958 aTwoPI=2.*M_PI;
959 dT=aT2-aT1;
960 //
99661617 961 Standard_Real aT1z = AdjustToPeriod (aT1, aTwoPI);
59495dbe 962 if (fabs(aT1z)<aEps) {
963 aT1z=0.;
964 }
965 //
99661617 966 Standard_Real aT2z = aT1z + dT;
59495dbe 967 if (fabs(aT2z-aTwoPI)<aEps) {
968 aT2z=aTwoPI;
969 }
99661617 970 //
59495dbe 971 for (i=0; i<aNbT; ++i) {
99661617 972 aT = pT[i];
973 // adjust aT to range [aT1z, aT1z + 2*PI]; note that pT[i] and aT1z
974 // are adjusted to range [0, 2*PI], but aT2z can be greater than 2*PI
975 aT = (aT < aT1z ? aT + aTwoPI : aT);
976 if (aT <= aT2z) {
59495dbe 977 D0(aT, aP2D);
978 aBox2D.Add(aP2D);
979 }
980 }
59495dbe 981}
99661617 982
59495dbe 983//=======================================================================
984//function : Compute
985//purpose :
986//=======================================================================
987Standard_Integer BndLib_Box2dCurve::Compute
988 (const Handle(Geom2d_Conic)& aConic2D,
989 const GeomAbs_CurveType aType,
990 Standard_Real *pT)
991{
992 Standard_Integer iRet, i, j;
993 Standard_Real aCosBt, aSinBt, aCosGm, aSinGm;
994 Standard_Real aLx, aLy;
995 //
996 iRet=0;
997 //
998 const gp_Ax22d& aPos=aConic2D->Position();
999 const gp_XY& aXDir=aPos.XDirection().XY();
1000 const gp_XY& aYDir=aPos.YDirection().XY();
1001 //
1002 aCosBt=aXDir.X();
1003 aSinBt=aXDir.Y();
1004 aCosGm=aYDir.X();
1005 aSinGm=aYDir.Y();
1006 //
1007 if (aType==GeomAbs_Circle || aType==GeomAbs_Ellipse) {
1008 Standard_Real aR1 = 0.0, aR2 = 0.0, aTwoPI = M_PI+M_PI;
1009 Standard_Real aA11 = 0.0, aA12 = 0.0, aA21 = 0.0, aA22 = 0.0;
1010 Standard_Real aBx = 0.0, aBy = 0.0, aB = 0.0, aCosFi = 0.0, aSinFi = 0.0, aFi = 0.0;
1011 //
1012 if(aType==GeomAbs_Ellipse) {
1013 Handle(Geom2d_Ellipse) aEL2D;
1014 //
1015 aEL2D=Handle(Geom2d_Ellipse)::DownCast(aConic2D);
1016 aR1=aEL2D->MajorRadius();
1017 aR2=aEL2D->MinorRadius();
1018 }
1019 else if(aType==GeomAbs_Circle) {
1020 Handle(Geom2d_Circle) aCR2D;
1021 //
1022 aCR2D=Handle(Geom2d_Circle)::DownCast(aConic2D);
1023 aR1=aCR2D->Radius();
1024 aR2=aR1;
1025 }
1026 //
1027 aA11=-aR1*aCosBt;
1028 aA12= aR2*aCosGm;
1029 aA21=-aR1*aSinBt;
1030 aA22= aR2*aSinGm;
1031 //
1032 for (i=0; i<2; ++i) {
1033 aLx=(!i) ? 0. : 1.;
1034 aLy=(!i) ? 1. : 0.;
1035 aBx=aLx*aA21-aLy*aA11;
1036 aBy=aLx*aA22-aLy*aA12;
1037 aB=sqrt(aBx*aBx+aBy*aBy);
1038 //
1039 aCosFi=aBx/aB;
1040 aSinFi=aBy/aB;
1041 //
1042 aFi=acos(aCosFi);
1043 if (aSinFi<0.) {
1044 aFi=aTwoPI-aFi;
7fd59977 1045 }
59495dbe 1046 //
1047 j=2*i;
1048 pT[j]=aTwoPI-aFi;
1049 pT[j]=AdjustToPeriod(pT[j], aTwoPI);
1050 //
1051 pT[j+1]=M_PI-aFi;
1052 pT[j+1]=AdjustToPeriod(pT[j+1], aTwoPI);
7fd59977 1053 }
59495dbe 1054 iRet=4;
1055 }//if (aType==GeomAbs_Ellipse) {
1056 //
1057 else if (aType==GeomAbs_Parabola) {
1058 Standard_Real aFc, aEps;
1059 Standard_Real aA1, aA2;
1060 Handle(Geom2d_Parabola) aPR2D;
1061 //
1062 aEps=1.e-12;
1063 //
1064 aPR2D=Handle(Geom2d_Parabola)::DownCast(aConic2D);
1065 aFc=aPR2D->Focal();
1066 //
1067 j=0;
1068 for (i=0; i<2; i++) {
1069 aLx=(!i) ? 0. : 1.;
1070 aLy=(!i) ? 1. : 0.;
1071 //
1072 aA2=aLx*aSinBt-aLy*aCosBt;
1073 if (fabs(aA2)<aEps) {
1074 continue;
1075 }
1076 //
1077 aA1=aLy*aCosGm-aLx*aSinGm;
1078 //
1079 pT[j]=2.*aFc*aA1/aA2;
1080 ++j;
1081 }
1082 iRet=j;
1083 }// else if (aType==GeomAbs_Parabola) {
1084 //
1085 else if (aType==GeomAbs_Hyperbola) {
1086 Standard_Integer k;
1087 Standard_Real aR1, aR2;
1088 Standard_Real aEps, aB1, aB2, aB12, aB22, aZ, aD;
1089 Handle(Geom2d_Hyperbola) aHP2D;
1090 //
1091 aEps=1.e-12;
1092 //
1093 aHP2D=Handle(Geom2d_Hyperbola)::DownCast(aConic2D);
1094 aR1=aHP2D->MajorRadius();
1095 aR2=aHP2D->MinorRadius();
1096 //
1097 j=0;
1098 for (i=0; i<2; i++) {
1099 aLx=(!i) ? 0. : 1.;
1100 aLy=(!i) ? 1. : 0.;
1101 //
1102 aB1=aR1*(aLx*aSinBt-aLy*aCosBt);
1103 aB2=aR2*(aLx*aSinGm-aLy*aCosGm);
1104 //
1105 if (fabs(aB1)<aEps) {
1106 continue;
1107 }
1108 //
1109 if (fabs(aB2)<aEps) {
1110 pT[j]=0.;
1111 ++j;
1112 }
1113 else {
1114 aB12=aB1*aB1;
1115 aB22=aB2*aB2;
1116 if (!(aB12>aB22)) {
1117 continue;
1118 }
1119 //
1120 aD=sqrt(aB12-aB22);
1121 //-------------
1122 for (k=-1; k<2; k+=2) {
1123 aZ=(aB1+k*aD)/aB2;
1124 if (fabs(aZ)<1.) {
1125 pT[j]=-log((1.+aZ)/(1.-aZ));
1126 ++j;
1127 }
1128 }
7fd59977 1129 }
7fd59977 1130 }
59495dbe 1131 iRet=j;
1132 }// else if (aType==GeomAbs_Hyperbola) {
1133 //
1134 return iRet;
1135}
1136//=======================================================================
1137//function : AdjustToPeriod
1138//purpose :
1139//=======================================================================
1140Standard_Real BndLib_Box2dCurve::AdjustToPeriod(const Standard_Real aT,
1141 const Standard_Real aPeriod)
1142{
1143 Standard_Integer k;
1144 Standard_Real aTRet;
1145 //
1146 aTRet=aT;
1147 if (aT<0.) {
1148 k=1+(Standard_Integer)(-aT/aPeriod);
1149 aTRet=aT+k*aPeriod;
7fd59977 1150 }
59495dbe 1151 else if (aT>aPeriod) {
1152 k=(Standard_Integer)(aT/aPeriod);
1153 aTRet=aT-k*aPeriod;
1154 }
1155 if (aTRet==aPeriod) {
1156 aTRet=0.;
1157 }
1158 return aTRet;
7fd59977 1159}
59495dbe 1160//
1161// myErrorStatus:
1162//
1163// -1 - object is just initialized
1164// 10 - myCurve is Null
1165// 12 - invalid range myT1 > myT2l
1166// 11 - unknown type of base curve
1167// 13 - offset curve can not be computed
1168//NMTTest
7fd59977 1169
59495dbe 1170//=======================================================================
1171//function : Add
1172//purpose :
1173//=======================================================================
1174void BndLib_Add2dCurve::Add(const Adaptor2d_Curve2d& aC,
1175 const Standard_Real aTol,
1176 Bnd_Box2d& aBox2D)
1177{
1178 BndLib_Add2dCurve::Add(aC,
1179 aC.FirstParameter(),
1180 aC.LastParameter (),
1181 aTol,
1182 aBox2D);
1183}
1184//=======================================================================
1185//function : Add
1186//purpose :
1187//=======================================================================
1188void BndLib_Add2dCurve::Add(const Adaptor2d_Curve2d& aC,
1189 const Standard_Real aU1,
1190 const Standard_Real aU2,
1191 const Standard_Real aTol,
1192 Bnd_Box2d& aBox2D)
1193{
1194 Adaptor2d_Curve2d *pC=(Adaptor2d_Curve2d *)&aC;
1195 Geom2dAdaptor_Curve *pA=dynamic_cast<Geom2dAdaptor_Curve*>(pC);
1196 if (!pA) {
1197 Standard_Real U, DU;
1198 Standard_Integer N, j;
1199 gp_Pnt2d P;
1200 N = 33;
1201 U = aU1;
1202 DU = (aU2-aU1)/(N-1);
1203 for (j=1; j<N; j++) {
1204 aC.D0(U,P);
1205 U+=DU;
1206 aBox2D.Add(P);
1207 }
1208 aC.D0(aU2,P);
1209 aBox2D.Add(P);
1210 aBox2D.Enlarge(aTol);
1211 return;
1212 }
1213 //
1214 const Handle(Geom2d_Curve)& aC2D=pA->Curve();
1215 //
1216 BndLib_Add2dCurve::Add(aC2D, aU1, aU2, aTol, aBox2D);
1217}
1218//=======================================================================
1219//function : Add
1220//purpose :
1221//=======================================================================
1222void BndLib_Add2dCurve::Add(const Handle(Geom2d_Curve)& aC2D,
1223 const Standard_Real aTol,
1224 Bnd_Box2d& aBox2D)
1225{
1226 Standard_Real aT1, aT2;
1227 //
1228 aT1=aC2D->FirstParameter();
1229 aT2=aC2D->LastParameter();
1230 //
1231 BndLib_Add2dCurve::Add(aC2D, aT1, aT2, aTol, aBox2D);
1232}
7fd59977 1233
59495dbe 1234//=======================================================================
1235//function : Add
1236//purpose :
1237//=======================================================================
1238void BndLib_Add2dCurve::Add(const Handle(Geom2d_Curve)& aC2D,
1239 const Standard_Real aT1,
1240 const Standard_Real aT2,
1241 const Standard_Real aTol,
1242 Bnd_Box2d& aBox2D)
1243{
1244 BndLib_Box2dCurve aBC;
1245 //
1246 aBC.SetCurve(aC2D);
1247 aBC.SetRange(aT1, aT2);
1248 //
1249 aBC.Perform();
1250 //
1251 const Bnd_Box2d& aBoxC=aBC.Box();
1252 aBox2D.Add(aBoxC);
1253 aBox2D.Enlarge(aTol);
1254}
3ba87fdb 1255//=======================================================================
1256//function : AddOptimal
1257//purpose :
1258//=======================================================================
1259void BndLib_Add2dCurve::AddOptimal(const Handle(Geom2d_Curve)& aC2D,
1260 const Standard_Real aT1,
1261 const Standard_Real aT2,
1262 const Standard_Real aTol,
1263 Bnd_Box2d& aBox2D)
1264{
1265 BndLib_Box2dCurve aBC;
1266 //
1267 aBC.SetCurve(aC2D);
1268 aBC.SetRange(aT1, aT2);
1269 //
1270 aBC.PerformOptimal(aTol);
1271 //
1272 const Bnd_Box2d& aBoxC=aBC.Box();
1273 aBox2D.Add(aBoxC);
1274 aBox2D.Enlarge(aTol);
1275}