1 // Copyright (c) 1996-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
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
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.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
16 #include <Bnd_Box.hxx>
18 #include <BndLib_Add3dCurve.hxx>
20 #include <Geom_BezierCurve.hxx>
21 #include <Geom_BSplineCurve.hxx>
22 #include <GeomAdaptor_Curve.hxx>
24 #include <Precision.hxx>
25 #include <TColgp_Array1OfPnt.hxx>
26 #include <TColStd_Array1OfReal.hxx>
27 #include <math_Function.hxx>
28 #include <math_PSO.hxx>
29 #include <math_BrentMinimum.hxx>
31 static Standard_Integer NbSamples(const Adaptor3d_Curve& C,
32 const Standard_Real Umin,
33 const Standard_Real Umax);
35 static Standard_Real AdjustExtr(const Adaptor3d_Curve& C,
36 const Standard_Real UMin,
37 const Standard_Real UMax,
38 const Standard_Real Extr0,
39 const Standard_Integer CoordIndx,
40 const Standard_Real Tol,
41 const Standard_Boolean IsMin);
44 //=======================================================================
45 //function : reduceSplineBox
46 //purpose : This method intended to reduce box in case of
47 // bezier and bspline curve.
48 //=======================================================================
49 static void reduceSplineBox(const Adaptor3d_Curve& theCurve,
50 const Bnd_Box& theOrigBox,
51 Bnd_Box & theReducedBox)
53 // Guaranteed bounding box based on poles of bspline.
55 Standard_Real aPolesXMin, aPolesYMin, aPolesZMin,
56 aPolesXMax, aPolesYMax, aPolesZMax;
58 if (theCurve.GetType() == GeomAbs_BSplineCurve)
60 Handle(Geom_BSplineCurve) aC = theCurve.BSpline();
61 const TColgp_Array1OfPnt& aPoles = aC->Poles();
63 for(Standard_Integer anIdx = aPoles.Lower();
64 anIdx <= aPoles.Upper();
67 aPolesBox.Add(aPoles.Value(anIdx));
70 if (theCurve.GetType() == GeomAbs_BezierCurve)
72 Handle(Geom_BezierCurve) aC = theCurve.Bezier();
73 const TColgp_Array1OfPnt& aPoles = aC->Poles();
75 for(Standard_Integer anIdx = aPoles.Lower();
76 anIdx <= aPoles.Upper();
79 aPolesBox.Add(aPoles.Value(anIdx));
83 aPolesBox.Get(aPolesXMin, aPolesYMin, aPolesZMin,
84 aPolesXMax, aPolesYMax, aPolesZMax);
86 Standard_Real x, y, z, X, Y, Z;
87 theOrigBox.Get(x, y, z, X, Y, Z);
105 theReducedBox.Update(x, y, z, X, Y, Z);
108 //=======================================================================
111 //=======================================================================
112 void BndLib_Add3dCurve::Add( const Adaptor3d_Curve& C,
113 const Standard_Real Tol,
116 BndLib_Add3dCurve::Add(C,
123 static Standard_Real FillBox(Bnd_Box& B, const Adaptor3d_Curve& C,
124 const Standard_Real first, const Standard_Real last,
125 const Standard_Integer N)
128 C.D0(first,P1); B.Add(P1);
129 Standard_Real p = first, dp = last-first, tol= 0.;
130 if(Abs(dp) > Precision::PConfusion()){
133 for(i = 1; i <= N; i++){
134 p += dp; C.D0(p,P2); B.Add(P2);
135 p += dp; C.D0(p,P3); B.Add(P3);
136 gp_Pnt Pc((P1.XYZ()+P3.XYZ())/2.0);
137 tol = Max(tol,Pc.Distance(P2));
141 C.D0(first,P1); B.Add(P1);
142 C.D0(last,P3); B.Add(P3);
148 //=======================================================================
151 //=======================================================================
153 void BndLib_Add3dCurve::Add( const Adaptor3d_Curve& C,
154 const Standard_Real U1,
155 const Standard_Real U2,
156 const Standard_Real Tol,
159 static Standard_Real weakness = 1.5; //OCC566(apo)
160 Standard_Real tol = 0.0;
161 switch (C.GetType()) {
165 BndLib::Add(C.Line(),U1,U2,Tol,B);
170 BndLib::Add(C.Circle(),U1,U2,Tol,B);
173 case GeomAbs_Ellipse:
175 BndLib::Add(C.Ellipse(),U1,U2,Tol,B);
178 case GeomAbs_Hyperbola:
180 BndLib::Add(C.Hyperbola(),U1,U2,Tol,B);
183 case GeomAbs_Parabola:
185 BndLib::Add(C.Parabola(),U1,U2,Tol,B);
188 case GeomAbs_BezierCurve:
190 Handle(Geom_BezierCurve) Bz = C.Bezier();
191 Standard_Integer N = Bz->Degree();
192 GeomAdaptor_Curve GACurve(Bz);
194 tol = FillBox(B1,GACurve,U1,U2,N);
195 B1.Enlarge(weakness*tol);
196 reduceSplineBox(C, B1, B);
200 case GeomAbs_BSplineCurve:
202 Handle(Geom_BSplineCurve) Bs = C.BSpline();
203 if(Abs(Bs->FirstParameter() - U1) > Precision::Parametric(Tol)||
204 Abs(Bs->LastParameter() - U2) > Precision::Parametric(Tol)) {
206 Handle(Geom_Geometry) G = Bs->Copy();
207 Handle(Geom_BSplineCurve) Bsaux (Handle(Geom_BSplineCurve)::DownCast (G));
208 Standard_Real u1 = U1, u2 = U2;
209 //// modified by jgv, 24.10.01 for BUC61031 ////
210 if (Bsaux->IsPeriodic())
211 ElCLib::AdjustPeriodic( Bsaux->FirstParameter(), Bsaux->LastParameter(), Precision::PConfusion(), u1, u2 );
213 ////////////////////////////////////////////////
214 // modified by NIZHNY-EAP Fri Dec 3 14:29:14 1999 ___BEGIN___
215 // To avoid exception in Segment
216 if(Bsaux->FirstParameter() > U1) u1 = Bsaux->FirstParameter();
217 if(Bsaux->LastParameter() < U2 ) u2 = Bsaux->LastParameter();
218 // modified by NIZHNY-EAP Fri Dec 3 14:29:18 1999 ___END___
220 Standard_Real aSegmentTol = 2. * Precision::PConfusion();
221 if (Abs(u2 - u1) < aSegmentTol)
222 aSegmentTol = Abs(u2 - u1) * 0.01;
223 Bsaux->Segment(u1, u2, aSegmentTol);
228 Standard_Integer k, k1 = Bs->FirstUKnotIndex(), k2 = Bs->LastUKnotIndex(),
229 N = Bs->Degree(), NbKnots = Bs->NbKnots();
230 TColStd_Array1OfReal Knots(1,NbKnots);
232 GeomAdaptor_Curve GACurve(Bs);
233 Standard_Real first = Knots(k1), last;
234 for(k = k1 + 1; k <= k2; k++){
236 tol = Max(FillBox(B1,GACurve,first,last,N), tol);
241 B1.Enlarge(weakness*tol);
242 reduceSplineBox(C, B1, B);
251 static Standard_Integer N = 33;
252 tol = FillBox(B1,C,U1,U2,N);
253 B1.Enlarge(weakness*tol);
254 Standard_Real x, y, z, X, Y, Z;
255 B1.Get(x, y, z, X, Y, Z);
256 B.Update(x, y, z, X, Y, Z);
262 //=======================================================================
263 //function : AddOptimal
265 //=======================================================================
267 void BndLib_Add3dCurve::AddOptimal( const Adaptor3d_Curve& C,
268 const Standard_Real Tol,
271 BndLib_Add3dCurve::AddOptimal(C,
277 //=======================================================================
278 //function : AddOptimal
280 //=======================================================================
282 void BndLib_Add3dCurve::AddOptimal( const Adaptor3d_Curve& C,
283 const Standard_Real U1,
284 const Standard_Real U2,
285 const Standard_Real Tol,
288 switch (C.GetType()) {
292 BndLib::Add(C.Line(),U1,U2,Tol,B);
297 BndLib::Add(C.Circle(),U1,U2,Tol,B);
300 case GeomAbs_Ellipse:
302 BndLib::Add(C.Ellipse(),U1,U2,Tol,B);
305 case GeomAbs_Hyperbola:
307 BndLib::Add(C.Hyperbola(),U1,U2,Tol,B);
310 case GeomAbs_Parabola:
312 BndLib::Add(C.Parabola(),U1,U2,Tol,B);
317 AddGenCurv(C, U1, U2, Tol, B);
322 //=======================================================================
323 //function : AddGenCurv
325 //=======================================================================
326 void BndLib_Add3dCurve::AddGenCurv(const Adaptor3d_Curve& C,
327 const Standard_Real UMin,
328 const Standard_Real UMax,
329 const Standard_Real Tol,
332 Standard_Integer Nu = NbSamples(C, UMin, UMax);
334 Standard_Real CoordMin[3] = {RealLast(), RealLast(), RealLast()};
335 Standard_Real CoordMax[3] = {-RealLast(), -RealLast(), -RealLast()};
336 Standard_Real DeflMax[3] = {-RealLast(), -RealLast(), -RealLast()};
339 Standard_Integer i, k;
340 Standard_Real du = (UMax-UMin)/(Nu-1), du2 = du / 2.;
341 NCollection_Array1<gp_XYZ> aPnts(1, Nu);
343 for (i = 1, u = UMin; i <= Nu; i++, u += du)
348 for(k = 0; k < 3; ++k)
350 if(CoordMin[k] > P.Coord(k+1))
352 CoordMin[k] = P.Coord(k+1);
354 if(CoordMax[k] < P.Coord(k+1))
356 CoordMax[k] = P.Coord(k+1);
362 gp_XYZ aPm = 0.5 * (aPnts(i-1) + aPnts(i));
364 gp_XYZ aD = (P.XYZ() - aPm);
365 for(k = 0; k < 3; ++k)
367 if(CoordMin[k] > P.Coord(k+1))
369 CoordMin[k] = P.Coord(k+1);
371 if(CoordMax[k] < P.Coord(k+1))
373 CoordMax[k] = P.Coord(k+1);
375 Standard_Real d = Abs(aD.Coord(k+1));
385 Standard_Real eps = Max(Tol, Precision::Confusion());
386 for(k = 0; k < 3; ++k)
388 Standard_Real d = DeflMax[k];
393 Standard_Real CMin = CoordMin[k];
394 Standard_Real CMax = CoordMax[k];
395 for(i = 1; i <= Nu; ++i)
397 if(aPnts(i).Coord(k+1) - CMin < d)
399 Standard_Real umin, umax;
400 umin = UMin + Max(0, i-2) * du;
401 umax = UMin + Min(Nu-1, i) * du;
402 Standard_Real cmin = AdjustExtr(C, umin, umax,
403 CMin, k + 1, eps, Standard_True);
409 else if(CMax - aPnts(i).Coord(k+1) < d)
411 Standard_Real umin, umax;
412 umin = UMin + Max(0, i-2) * du;
413 umax = UMin + Min(Nu-1, i) * du;
414 Standard_Real cmax = AdjustExtr(C, umin, umax,
415 CMax, k + 1, eps, Standard_False);
426 B.Add(gp_Pnt(CoordMin[0], CoordMin[1], CoordMin[2]));
427 B.Add(gp_Pnt(CoordMax[0], CoordMax[1], CoordMax[2]));
431 class CurvMaxMinCoordMVar : public math_MultipleVarFunction
434 CurvMaxMinCoordMVar(const Adaptor3d_Curve& theCurve,
435 const Standard_Real UMin,
436 const Standard_Real UMax,
437 const Standard_Integer CoordIndx,
438 const Standard_Real Sign)
442 myCoordIndx(CoordIndx),
447 Standard_Boolean Value (const math_Vector& X,
450 if (!CheckInputData(X(1)))
452 return Standard_False;
454 gp_Pnt aP = myCurve.Value(X(1));
456 F = mySign * aP.Coord(myCoordIndx);
458 return Standard_True;
463 Standard_Integer NbVariables() const
469 CurvMaxMinCoordMVar & operator = (const CurvMaxMinCoordMVar & theOther);
471 Standard_Boolean CheckInputData(Standard_Real theParam)
473 if (theParam < myUMin ||
475 return Standard_False;
476 return Standard_True;
479 const Adaptor3d_Curve& myCurve;
480 Standard_Real myUMin;
481 Standard_Real myUMax;
482 Standard_Integer myCoordIndx;
483 Standard_Real mySign;
486 class CurvMaxMinCoord : public math_Function
489 CurvMaxMinCoord(const Adaptor3d_Curve& theCurve,
490 const Standard_Real UMin,
491 const Standard_Real UMax,
492 const Standard_Integer CoordIndx,
493 const Standard_Real Sign)
497 myCoordIndx(CoordIndx),
502 Standard_Boolean Value (const Standard_Real X,
505 if (!CheckInputData(X))
507 return Standard_False;
509 gp_Pnt aP = myCurve.Value(X);
511 F = mySign * aP.Coord(myCoordIndx);
513 return Standard_True;
517 CurvMaxMinCoord & operator = (const CurvMaxMinCoord & theOther);
519 Standard_Boolean CheckInputData(Standard_Real theParam)
521 if (theParam < myUMin ||
523 return Standard_False;
524 return Standard_True;
527 const Adaptor3d_Curve& myCurve;
528 Standard_Real myUMin;
529 Standard_Real myUMax;
530 Standard_Integer myCoordIndx;
531 Standard_Real mySign;
534 //=======================================================================
535 //function : AdjustExtr
537 //=======================================================================
539 Standard_Real AdjustExtr(const Adaptor3d_Curve& C,
540 const Standard_Real UMin,
541 const Standard_Real UMax,
542 const Standard_Real Extr0,
543 const Standard_Integer CoordIndx,
544 const Standard_Real Tol,
545 const Standard_Boolean IsMin)
547 Standard_Real aSign = IsMin ? 1.:-1.;
548 Standard_Real extr = aSign * Extr0;
550 Standard_Real uTol = Max(C.Resolution(Tol), Precision::PConfusion());
551 Standard_Real Du = (C.LastParameter() - C.FirstParameter());
553 Standard_Real reltol = uTol / Max(Abs(UMin), Abs(UMax));
554 if(UMax - UMin < 0.01 * Du)
557 math_BrentMinimum anOptLoc(reltol, 100, uTol);
558 CurvMaxMinCoord aFunc(C, UMin, UMax, CoordIndx, aSign);
559 anOptLoc.Perform(aFunc, UMin, (UMin+UMax)/2., UMax);
560 if(anOptLoc.IsDone())
562 extr = anOptLoc.Minimum();
567 Standard_Integer aNbParticles = Max(8, RealToInt(32 * (UMax - UMin) / Du));
568 Standard_Real maxstep = (UMax - UMin) / (aNbParticles + 1);
570 math_Vector aLowBorder(1,1);
571 math_Vector aUppBorder(1,1);
572 math_Vector aSteps(1,1);
573 aLowBorder(1) = UMin;
574 aUppBorder(1) = UMax;
575 aSteps(1) = Min(0.1 * Du, maxstep);
577 CurvMaxMinCoordMVar aFunc(C, UMin, UMax, CoordIndx, aSign);
578 math_PSO aFinder(&aFunc, aLowBorder, aUppBorder, aSteps, aNbParticles);
579 aFinder.Perform(aSteps, extr, aT);
581 math_BrentMinimum anOptLoc(reltol, 100, uTol);
582 CurvMaxMinCoord aFunc1(C, UMin, UMax, CoordIndx, aSign);
583 anOptLoc.Perform(aFunc1, Max(aT(1) - aSteps(1), UMin), aT(1), Min(aT(1) + aSteps(1), UMax));
585 if(anOptLoc.IsDone())
587 extr = anOptLoc.Minimum();
594 //=======================================================================
595 //function : NbSamples
597 //=======================================================================
599 Standard_Integer NbSamples(const Adaptor3d_Curve& C,
600 const Standard_Real Umin,
601 const Standard_Real Umax)
604 GeomAbs_CurveType Type = C.GetType();
606 case GeomAbs_BezierCurve:
609 //By default parametric range of Bezier curv is [0, 1]
610 Standard_Real du = Umax - Umin;
613 N = RealToInt(du*N) + 1;
618 case GeomAbs_BSplineCurve:
620 const Handle(Geom_BSplineCurve)& BC = C.BSpline();
621 N = 2 * (BC->Degree() + 1)*(BC->NbKnots() -1);
622 Standard_Real umin = BC->FirstParameter(),
623 umax = BC->LastParameter();
624 Standard_Real du = (Umax - Umin) / (umax - umin);
627 N = RealToInt(du*N) + 1;