From: azv Date: Fri, 5 Aug 2016 12:21:34 +0000 (+0300) Subject: 0027074: Support of multi-span cache in Geom[2d]Adaptor X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=be887d7884d4c14a3b0763c357506ae046e4e2a9;p=occt-copy.git 0027074: Support of multi-span cache in Geom[2d]Adaptor The multi-span cache is stored as matrix (for surface) or vector (for curves) of caches. Each cell corresponds to a span. The cache is initialized on first call and destroyed when adaptor is destroyed. 1. Multi-span cache for curve and surfaces. 2. Revision of BSplSLib_Cache and small improvements. 3. Renew cache when loading same curve/surface into adaptor. 4. Optimizations for single-span cache 5. Remove unused constructors in BSpl*Lib_Cache classes 6. Allocate cache on first call, not when loading a curve/surface 7. Note in upgrade.md about multi-span implementation --- diff --git a/dox/dev_guides/upgrade/upgrade.md b/dox/dev_guides/upgrade/upgrade.md index 7adfb09851..c330b6997d 100644 --- a/dox/dev_guides/upgrade/upgrade.md +++ b/dox/dev_guides/upgrade/upgrade.md @@ -1222,3 +1222,11 @@ Method Graphic3d_CView::Update() does not redraw the view and does not re-comput * The classes *BOPDS_PassKey* and *BOPDS_PassKeyBoolean* are too excessive and not used any more in Boolean Operations. To replace them the new *BOPDS_Pair* class has been implemented. Thus: - The method *BOPDS_DS::Interferences()* now returns the *BOPDS_MapOfPair*; - The method *BOPDS_Iterator::Value()* takes now only two parameters - the indices of interfering sub-shapes. +Methods *TObj_Model::SaveAs* and *TObj_Model::Load* receive *TCollection_ExtendedString* filename arguments instead of char*. This shows that the filename may be not-ASCII explicitly. Also it makes OCAF API related to this functionality more conform. + +@subsection upgrade_occt710_multispan Multi-span cache support in *Geom2dAdaptor_Curve, GeomAdaptor_Curve* and *GeomAdaptor_Surface* + +Multi-span cache has been implemented in *Geom2dAdaptor_Curve, GeomAdaptor_Curve* and *GeomAdaptor_Surface*. Cache for each span is collected first time to evaluate this span. + +The benefit of this change is decreased time of calculations (up to 5 times) on some cases. + diff --git a/src/BSplCLib/BSplCLib_Cache.cxx b/src/BSplCLib/BSplCLib_Cache.cxx index 59efb2f8f1..39e419bacf 100644 --- a/src/BSplCLib/BSplCLib_Cache.cxx +++ b/src/BSplCLib/BSplCLib_Cache.cxx @@ -33,88 +33,32 @@ static Standard_Real* ConvertArray(const Handle(TColStd_HArray2OfReal)& theHArra BSplCLib_Cache::BSplCLib_Cache() + : myIsRational(Standard_False), + mySpanStart(0.0), + mySpanLength(0.0), + mySpanIndex(0), + mySpanIndexMin(0), + mySpanIndexMax(0), + myDegree(0) { - myPolesWeights.Nullify(); - myIsRational = Standard_False; - mySpanStart = 0.0; - mySpanLength = 0.0; - mySpanIndex = 0; - myDegree = 0; - myFlatKnots.Nullify(); -} - -BSplCLib_Cache::BSplCLib_Cache(const Standard_Integer& theDegree, - const Standard_Boolean& thePeriodic, - const TColStd_Array1OfReal& theFlatKnots, - const TColgp_Array1OfPnt2d& thePoles2d, - const TColStd_Array1OfReal* theWeights) -{ - Standard_Real aCacheParam = theFlatKnots.Value(theFlatKnots.Lower() + theDegree); - BuildCache(aCacheParam, theDegree, thePeriodic, - theFlatKnots, thePoles2d, theWeights); -} - -BSplCLib_Cache::BSplCLib_Cache(const Standard_Integer& theDegree, - const Standard_Boolean& thePeriodic, - const TColStd_Array1OfReal& theFlatKnots, - const TColgp_Array1OfPnt& thePoles, - const TColStd_Array1OfReal* theWeights) -{ - Standard_Real aCacheParam = theFlatKnots.Value(theFlatKnots.Lower() + theDegree); - BuildCache(aCacheParam, theDegree, thePeriodic, - theFlatKnots, thePoles, theWeights); } Standard_Boolean BSplCLib_Cache::IsCacheValid(Standard_Real theParameter) const { - Standard_Real aNewParam = theParameter; - if (!myFlatKnots.IsNull()) - PeriodicNormalization(myFlatKnots->Array1(), aNewParam); - - Standard_Real aDelta = aNewParam - mySpanStart; + Standard_Real aDelta = theParameter - mySpanStart; return ((aDelta >= 0.0 || mySpanIndex == mySpanIndexMin) && (aDelta < mySpanLength || mySpanIndex == mySpanIndexMax)); } -void BSplCLib_Cache::PeriodicNormalization(const TColStd_Array1OfReal& theFlatKnots, - Standard_Real& theParameter) const -{ - Standard_Real aPeriod = theFlatKnots.Value(theFlatKnots.Upper() - myDegree) - - theFlatKnots.Value(myDegree + 1) ; - if (theParameter < theFlatKnots.Value(myDegree + 1)) - { - Standard_Real aScale = IntegerPart( - (theFlatKnots.Value(myDegree + 1) - theParameter) / aPeriod); - theParameter += aPeriod * (aScale + 1.0); - } - if (theParameter > theFlatKnots.Value(theFlatKnots.Upper() - myDegree)) - { - Standard_Real aScale = IntegerPart( - (theParameter - theFlatKnots.Value(theFlatKnots.Upper() - myDegree)) / aPeriod); - theParameter -= aPeriod * (aScale + 1.0); - } -} - -void BSplCLib_Cache::BuildCache(const Standard_Real& theParameter, - const Standard_Integer& theDegree, - const Standard_Boolean& thePeriodic, - const TColStd_Array1OfReal& theFlatKnots, - const TColgp_Array1OfPnt2d& thePoles2d, - const TColStd_Array1OfReal* theWeights) +void BSplCLib_Cache::BuildCache(const Standard_Integer theDegree, + const Standard_Boolean thePeriodic, + const TColStd_Array1OfReal& theFlatKnots, + const Standard_Integer theCachedSpan, + const TColgp_Array1OfPnt2d& thePoles2d, + const TColStd_Array1OfReal* theWeights) { - // Normalize theParameter for periodical B-splines - Standard_Real aNewParam = theParameter; - if (thePeriodic) - { - PeriodicNormalization(theFlatKnots, aNewParam); - myFlatKnots = new TColStd_HArray1OfReal(1, theFlatKnots.Length()); - myFlatKnots->ChangeArray1() = theFlatKnots; - } - else if (!myFlatKnots.IsNull()) // Periodical curve became non-periodical - myFlatKnots.Nullify(); - // Change the size of cached data if needed myIsRational = (theWeights != NULL); Standard_Integer aPWColNumber = myIsRational ? 3 : 2; @@ -122,9 +66,7 @@ void BSplCLib_Cache::BuildCache(const Standard_Real& theParameter, myPolesWeights = new TColStd_HArray2OfReal(1, theDegree + 1, 1, aPWColNumber); myDegree = theDegree; - mySpanIndex = 0; - BSplCLib::LocateParameter(theDegree, theFlatKnots, BSplCLib::NoMults(), - aNewParam, thePeriodic, mySpanIndex, aNewParam); + mySpanIndex = theCachedSpan; mySpanStart = theFlatKnots.Value(mySpanIndex); mySpanLength = theFlatKnots.Value(mySpanIndex + 1) - mySpanStart; mySpanIndexMin = thePeriodic ? 0 : myDegree + 1; @@ -136,24 +78,13 @@ void BSplCLib_Cache::BuildCache(const Standard_Real& theParameter, myPolesWeights->ChangeArray2()); } -void BSplCLib_Cache::BuildCache(const Standard_Real& theParameter, - const Standard_Integer& theDegree, - const Standard_Boolean& thePeriodic, - const TColStd_Array1OfReal& theFlatKnots, - const TColgp_Array1OfPnt& thePoles, - const TColStd_Array1OfReal* theWeights) +void BSplCLib_Cache::BuildCache(const Standard_Integer theDegree, + const Standard_Boolean thePeriodic, + const TColStd_Array1OfReal& theFlatKnots, + const Standard_Integer theCachedSpan, + const TColgp_Array1OfPnt& thePoles, + const TColStd_Array1OfReal* theWeights) { - // Create list of knots with repetitions and normalize theParameter for periodical B-splines - Standard_Real aNewParam = theParameter; - if (thePeriodic) - { - PeriodicNormalization(theFlatKnots, aNewParam); - myFlatKnots = new TColStd_HArray1OfReal(1, theFlatKnots.Length()); - myFlatKnots->ChangeArray1() = theFlatKnots; - } - else if (!myFlatKnots.IsNull()) // Periodical curve became non-periodical - myFlatKnots.Nullify(); - // Change the size of cached data if needed myIsRational = (theWeights != NULL); Standard_Integer aPWColNumber = myIsRational ? 4 : 3; @@ -161,9 +92,7 @@ void BSplCLib_Cache::BuildCache(const Standard_Real& theParameter, myPolesWeights = new TColStd_HArray2OfReal(1, theDegree + 1, 1, aPWColNumber); myDegree = theDegree; - mySpanIndex = 0; - BSplCLib::LocateParameter(theDegree, theFlatKnots, BSplCLib::NoMults(), - aNewParam, thePeriodic, mySpanIndex, aNewParam); + mySpanIndex = theCachedSpan; mySpanStart = theFlatKnots.Value(mySpanIndex); mySpanLength = theFlatKnots.Value(mySpanIndex + 1) - mySpanStart; mySpanIndexMin = thePeriodic ? 0 : myDegree + 1; @@ -176,15 +105,11 @@ void BSplCLib_Cache::BuildCache(const Standard_Real& theParameter, } -void BSplCLib_Cache::CalculateDerivative(const Standard_Real& theParameter, - const Standard_Integer& theDerivative, - Standard_Real& theDerivArray) const +void BSplCLib_Cache::CalculateDerivative(const Standard_Real theParameter, + const Standard_Integer theDerivative, + Standard_Real& theDerivArray) const { - Standard_Real aNewParameter = theParameter; - if (!myFlatKnots.IsNull()) // B-spline is periodical - PeriodicNormalization(myFlatKnots->Array1(), aNewParameter); - aNewParameter = (aNewParameter - mySpanStart) / mySpanLength; - + Standard_Real aNewParameter = (theParameter - mySpanStart) / mySpanLength; Standard_Real* aPolesArray = ConvertArray(myPolesWeights); Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns @@ -225,13 +150,9 @@ void BSplCLib_Cache::CalculateDerivative(const Standard_Real& theParameter, } -void BSplCLib_Cache::D0(const Standard_Real& theParameter, gp_Pnt2d& thePoint) const +void BSplCLib_Cache::D0(const Standard_Real theParameter, gp_Pnt2d& thePoint) const { - Standard_Real aNewParameter = theParameter; - if (!myFlatKnots.IsNull()) // B-spline is periodical - PeriodicNormalization(myFlatKnots->Array1(), aNewParameter); - aNewParameter = (aNewParameter - mySpanStart) / mySpanLength; - + Standard_Real aNewParameter = (theParameter - mySpanStart) / mySpanLength; Standard_Real* aPolesArray = ConvertArray(myPolesWeights); Standard_Real aPoint[4]; Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns @@ -245,13 +166,9 @@ void BSplCLib_Cache::D0(const Standard_Real& theParameter, gp_Pnt2d& thePoint) c thePoint.ChangeCoord().Divide(aPoint[2]); } -void BSplCLib_Cache::D0(const Standard_Real& theParameter, gp_Pnt& thePoint) const +void BSplCLib_Cache::D0(const Standard_Real theParameter, gp_Pnt& thePoint) const { - Standard_Real aNewParameter = theParameter; - if (!myFlatKnots.IsNull()) // B-spline is periodical - PeriodicNormalization(myFlatKnots->Array1(), aNewParameter); - aNewParameter = (aNewParameter - mySpanStart) / mySpanLength; - + Standard_Real aNewParameter = (theParameter - mySpanStart) / mySpanLength; Standard_Real* aPolesArray = ConvertArray(myPolesWeights); Standard_Real aPoint[4]; Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns @@ -266,12 +183,12 @@ void BSplCLib_Cache::D0(const Standard_Real& theParameter, gp_Pnt& thePoint) con } -void BSplCLib_Cache::D1(const Standard_Real& theParameter, gp_Pnt2d& thePoint, gp_Vec2d& theTangent) const +void BSplCLib_Cache::D1(const Standard_Real theParameter, gp_Pnt2d& thePoint, gp_Vec2d& theTangent) const { Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns Standard_Real aPntDeriv[8]; // result storage (point and derivative coordinates) - this->CalculateDerivative(theParameter, 1, aPntDeriv[0]); + CalculateDerivative(theParameter, 1, aPntDeriv[0]); if (myIsRational) // the size of aPntDeriv was changed by PLib::RationalDerivative aDimension -= 1; @@ -279,12 +196,12 @@ void BSplCLib_Cache::D1(const Standard_Real& theParameter, gp_Pnt2d& thePoint, g theTangent.SetCoord(aPntDeriv[aDimension], aPntDeriv[aDimension + 1]); } -void BSplCLib_Cache::D1(const Standard_Real& theParameter, gp_Pnt& thePoint, gp_Vec& theTangent) const +void BSplCLib_Cache::D1(const Standard_Real theParameter, gp_Pnt& thePoint, gp_Vec& theTangent) const { Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns Standard_Real aPntDeriv[8]; // result storage (point and derivative coordinates) - this->CalculateDerivative(theParameter, 1, aPntDeriv[0]); + CalculateDerivative(theParameter, 1, aPntDeriv[0]); if (myIsRational) // the size of aPntDeriv was changed by PLib::RationalDerivative aDimension -= 1; @@ -292,12 +209,12 @@ void BSplCLib_Cache::D1(const Standard_Real& theParameter, gp_Pnt& thePoint, gp_ theTangent.SetCoord(aPntDeriv[aDimension], aPntDeriv[aDimension + 1], aPntDeriv[aDimension + 2]); } -void BSplCLib_Cache::D2(const Standard_Real& theParameter, gp_Pnt2d& thePoint, gp_Vec2d& theTangent, gp_Vec2d& theCurvature) const +void BSplCLib_Cache::D2(const Standard_Real theParameter, gp_Pnt2d& thePoint, gp_Vec2d& theTangent, gp_Vec2d& theCurvature) const { Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns Standard_Real aPntDeriv[12]; // result storage (point and derivatives coordinates) - this->CalculateDerivative(theParameter, 2, aPntDeriv[0]); + CalculateDerivative(theParameter, 2, aPntDeriv[0]); if (myIsRational) // the size of aPntDeriv was changed by PLib::RationalDerivative aDimension -= 1; @@ -306,12 +223,12 @@ void BSplCLib_Cache::D2(const Standard_Real& theParameter, gp_Pnt2d& thePoint, g theCurvature.SetCoord(aPntDeriv[aDimension<<1], aPntDeriv[(aDimension<<1) + 1]); } -void BSplCLib_Cache::D2(const Standard_Real& theParameter, gp_Pnt& thePoint, gp_Vec& theTangent, gp_Vec& theCurvature) const +void BSplCLib_Cache::D2(const Standard_Real theParameter, gp_Pnt& thePoint, gp_Vec& theTangent, gp_Vec& theCurvature) const { Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns Standard_Real aPntDeriv[12]; // result storage (point and derivatives coordinates) - this->CalculateDerivative(theParameter, 2, aPntDeriv[0]); + CalculateDerivative(theParameter, 2, aPntDeriv[0]); if (myIsRational) // the size of aPntDeriv was changed by PLib::RationalDerivative aDimension -= 1; @@ -321,16 +238,16 @@ void BSplCLib_Cache::D2(const Standard_Real& theParameter, gp_Pnt& thePoint, gp_ } -void BSplCLib_Cache::D3(const Standard_Real& theParameter, - gp_Pnt2d& thePoint, - gp_Vec2d& theTangent, - gp_Vec2d& theCurvature, - gp_Vec2d& theTorsion) const +void BSplCLib_Cache::D3(const Standard_Real theParameter, + gp_Pnt2d& thePoint, + gp_Vec2d& theTangent, + gp_Vec2d& theCurvature, + gp_Vec2d& theTorsion) const { Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns Standard_Real aPntDeriv[16]; // result storage (point and derivatives coordinates) - this->CalculateDerivative(theParameter, 3, aPntDeriv[0]); + CalculateDerivative(theParameter, 3, aPntDeriv[0]); if (myIsRational) // the size of aPntDeriv was changed by PLib::RationalDerivative aDimension -= 1; @@ -342,16 +259,16 @@ void BSplCLib_Cache::D3(const Standard_Real& theParameter, theTorsion.SetCoord(aPntDeriv[aShift], aPntDeriv[aShift + 1]); } -void BSplCLib_Cache::D3(const Standard_Real& theParameter, - gp_Pnt& thePoint, - gp_Vec& theTangent, - gp_Vec& theCurvature, - gp_Vec& theTorsion) const +void BSplCLib_Cache::D3(const Standard_Real theParameter, + gp_Pnt& thePoint, + gp_Vec& theTangent, + gp_Vec& theCurvature, + gp_Vec& theTorsion) const { Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns Standard_Real aPntDeriv[16]; // result storage (point and derivatives coordinates) - this->CalculateDerivative(theParameter, 3, aPntDeriv[0]); + CalculateDerivative(theParameter, 3, aPntDeriv[0]); if (myIsRational) // the size of aPntDeriv was changed by PLib::RationalDerivative aDimension -= 1; diff --git a/src/BSplCLib/BSplCLib_Cache.hxx b/src/BSplCLib/BSplCLib_Cache.hxx index 74bcd14d00..4c5a0e0acb 100644 --- a/src/BSplCLib/BSplCLib_Cache.hxx +++ b/src/BSplCLib/BSplCLib_Cache.hxx @@ -40,86 +40,64 @@ class BSplCLib_Cache : public Standard_Transient public: //! Default constructor Standard_EXPORT BSplCLib_Cache(); - //! Constructor for caching of 2D curves - //! \param theDegree degree of the curve - //! \param thePeriodic identify the curve is periodic - //! \param theFlatKnots knots of Bezier/B-spline curve (with repetitions) - //! \param thePoles2d array of poles of 2D curve - //! \param theWeights array of weights of corresponding poles - Standard_EXPORT BSplCLib_Cache(const Standard_Integer& theDegree, - const Standard_Boolean& thePeriodic, - const TColStd_Array1OfReal& theFlatKnots, - const TColgp_Array1OfPnt2d& thePoles2d, - const TColStd_Array1OfReal* theWeights = NULL); - //! Constructor for caching of 3D curves - //! \param theDegree degree of the curve - //! \param thePeriodic identify the curve is periodic - //! \param theFlatKnots knots of Bezier/B-spline curve (with repetitions) - //! \param thePoles array of poles of 3D curve - //! \param theWeights array of weights of corresponding poles - Standard_EXPORT BSplCLib_Cache(const Standard_Integer& theDegree, - const Standard_Boolean& thePeriodic, - const TColStd_Array1OfReal& theFlatKnots, - const TColgp_Array1OfPnt& thePoles, - const TColStd_Array1OfReal* theWeights = NULL); //! Verifies validity of the cache using flat parameter of the point //! \param theParameter parameter of the point placed in the span Standard_EXPORT Standard_Boolean IsCacheValid(Standard_Real theParameter) const; //! Recomputes the cache data for 2D curves. Does not verify validity of the cache - //! \param theParameter the value on the knot's axis to identify the span //! \param theDegree degree of the curve //! \param thePeriodic identify the curve is periodic //! \param theFlatKnots knots of Bezier/B-spline curve (with repetitions) + //! \param theCachedSpan index of span to be cached //! \param thePoles2d array of poles of 2D curve //! \param theWeights array of weights of corresponding poles - Standard_EXPORT void BuildCache(const Standard_Real& theParameter, - const Standard_Integer& theDegree, - const Standard_Boolean& thePeriodic, - const TColStd_Array1OfReal& theFlatKnots, - const TColgp_Array1OfPnt2d& thePoles2d, - const TColStd_Array1OfReal* theWeights = NULL); + Standard_EXPORT void BuildCache(const Standard_Integer theDegree, + const Standard_Boolean thePeriodic, + const TColStd_Array1OfReal& theFlatKnots, + const Standard_Integer theCachedSpan, + const TColgp_Array1OfPnt2d& thePoles2d, + const TColStd_Array1OfReal* theWeights = NULL); //! Recomputes the cache data for 3D curves. Does not verify validity of the cache - //! \param theParameter the value on the knot's axis to identify the span //! \param theDegree degree of the curve //! \param thePeriodic identify the curve is periodic //! \param theFlatKnots knots of Bezier/B-spline curve (with repetitions) + //! \param theCachedSpan index of span to be cached //! \param thePoles array of poles of 3D curve //! \param theWeights array of weights of corresponding poles - Standard_EXPORT void BuildCache(const Standard_Real& theParameter, - const Standard_Integer& theDegree, - const Standard_Boolean& thePeriodic, - const TColStd_Array1OfReal& theFlatKnots, - const TColgp_Array1OfPnt& thePoles, - const TColStd_Array1OfReal* theWeights = NULL); + Standard_EXPORT void BuildCache(const Standard_Integer theDegree, + const Standard_Boolean thePeriodic, + const TColStd_Array1OfReal& theFlatKnots, + const Standard_Integer theCachedSpan, + const TColgp_Array1OfPnt& thePoles, + const TColStd_Array1OfReal* theWeights = NULL); //! Calculates the point on the curve in the specified parameter //! \param[in] theParameter parameter of calculation of the value //! \param[out] thePoint the result of calculation (the point on the curve) - Standard_EXPORT void D0(const Standard_Real& theParameter, gp_Pnt2d& thePoint) const; - Standard_EXPORT void D0(const Standard_Real& theParameter, gp_Pnt& thePoint) const; + Standard_EXPORT void D0(const Standard_Real theParameter, gp_Pnt2d& thePoint) const; + Standard_EXPORT void D0(const Standard_Real theParameter, gp_Pnt& thePoint) const; //! Calculates the point on the curve and its first derivative in the specified parameter //! \param[in] theParameter parameter of calculation of the value //! \param[out] thePoint the result of calculation (the point on the curve) //! \param[out] theTangent tangent vector (first derivatives) for the curve in the calculated point - Standard_EXPORT void D1(const Standard_Real& theParameter, gp_Pnt2d& thePoint, gp_Vec2d& theTangent) const; - Standard_EXPORT void D1(const Standard_Real& theParameter, gp_Pnt& thePoint, gp_Vec& theTangent) const; + Standard_EXPORT void D1(const Standard_Real theParameter, gp_Pnt2d& thePoint, gp_Vec2d& theTangent) const; + Standard_EXPORT void D1(const Standard_Real theParameter, gp_Pnt& thePoint, gp_Vec& theTangent) const; //! Calculates the point on the curve and two derivatives in the specified parameter //! \param[in] theParameter parameter of calculation of the value //! \param[out] thePoint the result of calculation (the point on the curve) //! \param[out] theTangent tangent vector (1st derivatives) for the curve in the calculated point //! \param[out] theCurvature curvature vector (2nd derivatives) for the curve in the calculated point - Standard_EXPORT void D2(const Standard_Real& theParameter, - gp_Pnt2d& thePoint, - gp_Vec2d& theTangent, - gp_Vec2d& theCurvature) const; - Standard_EXPORT void D2(const Standard_Real& theParameter, - gp_Pnt& thePoint, - gp_Vec& theTangent, - gp_Vec& theCurvature) const; + Standard_EXPORT void D2(const Standard_Real theParameter, + gp_Pnt2d& thePoint, + gp_Vec2d& theTangent, + gp_Vec2d& theCurvature) const; + Standard_EXPORT void D2(const Standard_Real theParameter, + gp_Pnt& thePoint, + gp_Vec& theTangent, + gp_Vec& theCurvature) const; //! Calculates the point on the curve and three derivatives in the specified parameter //! \param[in] theParameter parameter of calculation of the value @@ -127,34 +105,29 @@ public: //! \param[out] theTangent tangent vector (1st derivatives) for the curve in the calculated point //! \param[out] theCurvature curvature vector (2nd derivatives) for the curve in the calculated point //! \param[out] theTorsion second curvature vector (3rd derivatives) for the curve in the calculated point - Standard_EXPORT void D3(const Standard_Real& theParameter, - gp_Pnt2d& thePoint, - gp_Vec2d& theTangent, - gp_Vec2d& theCurvature, - gp_Vec2d& theTorsion) const; - Standard_EXPORT void D3(const Standard_Real& theParameter, - gp_Pnt& thePoint, - gp_Vec& theTangent, - gp_Vec& theCurvature, - gp_Vec& theTorsion) const; + Standard_EXPORT void D3(const Standard_Real theParameter, + gp_Pnt2d& thePoint, + gp_Vec2d& theTangent, + gp_Vec2d& theCurvature, + gp_Vec2d& theTorsion) const; + Standard_EXPORT void D3(const Standard_Real theParameter, + gp_Pnt& thePoint, + gp_Vec& theTangent, + gp_Vec& theCurvature, + gp_Vec& theTorsion) const; DEFINE_STANDARD_RTTIEXT(BSplCLib_Cache,Standard_Transient) protected: - //! Normalizes the parameter for periodical curves - //! \param theFlatKnots knots with repetitions - //! \param theParameter the value to be normalized into the knots array - void PeriodicNormalization(const TColStd_Array1OfReal& theFlatKnots, Standard_Real& theParameter) const; - //! Fills array of derivatives in the selected point of the curve //! \param[in] theParameter parameter of the calculation //! \param[in] theDerivative maximal derivative to be calculated (computes all derivatives lesser than specified) //! \param[out] theDerivArray result array of derivatives (with size (theDerivative+1)*(PntDim+1), //! where PntDim = 2 or 3 is a dimension of the curve) - void CalculateDerivative(const Standard_Real& theParameter, - const Standard_Integer& theDerivative, - Standard_Real& theDerivArray) const; + void CalculateDerivative(const Standard_Real theParameter, + const Standard_Integer theDerivative, + Standard_Real& theDerivArray) const; private: Handle(TColStd_HArray2OfReal) myPolesWeights; ///< array of poles and weights of calculated cache @@ -163,14 +136,13 @@ private: // x2 y2 [z2] [w2] etc // for 2D-curves there is no z conponent, for non-rational curves there is no weight - Standard_Boolean myIsRational; ///< identifies the rationality of Bezier/B-spline curve - Standard_Real mySpanStart; ///< parameter for the first point of the span - Standard_Real mySpanLength; ///< length of the span - Standard_Integer mySpanIndex; ///< index of the span on Bezier/B-spline curve + Standard_Boolean myIsRational; ///< identifies the rationality of Bezier/B-spline curve + Standard_Real mySpanStart; ///< parameter for the first point of the span + Standard_Real mySpanLength; ///< length of the span + Standard_Integer mySpanIndex; ///< index of the span on Bezier/B-spline curve Standard_Integer mySpanIndexMin; ///< minimal index of span on Bezier/B-spline curve Standard_Integer mySpanIndexMax; ///< maximal number of spans on Bezier/B-spline curve - Standard_Integer myDegree; ///< degree of Bezier/B-spline - Handle(TColStd_HArray1OfReal) myFlatKnots; ///< knots of Bezier/B-spline (used for periodic normalization of parameters, exists only for periodical splines) + Standard_Integer myDegree; ///< degree of Bezier/B-spline }; DEFINE_STANDARD_HANDLE(BSplCLib_Cache, Standard_Transient) diff --git a/src/BSplCLib/BSplCLib_MultiSpanCache.gxx b/src/BSplCLib/BSplCLib_MultiSpanCache.gxx new file mode 100644 index 0000000000..c604f5c1a4 --- /dev/null +++ b/src/BSplCLib/BSplCLib_MultiSpanCache.gxx @@ -0,0 +1,158 @@ +// Copyright (c) 2014 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include +#include + +template +BSplCLib_MultiSpanCacheBase::BSplCLib_MultiSpanCacheBase( + const Standard_Integer theDegree, + const Standard_Boolean thePeriodic, + const Array1OfPOINT& thePoles, + const TColStd_Array1OfReal* theWeights) + : myDegree(theDegree), + myPeriodic(thePeriodic), + myFirstKnot(0.), + myLastKnot(1.), + myKnots(NULL), + myMults(NULL), + myFlatKnots(NULL), + myPoles(thePoles), + myWeights(theWeights), + mySingleSpan(Standard_True), + myCaches(1), + myLastCacheInd(0) +{ + // Build cache for single span + TColStd_Array1OfReal aFlatKnots(BSplCLib::FlatBezierKnots(myDegree), 1, (myDegree + 1) * 2); + myCaches[myLastCacheInd] = new BSplCLib_Cache; + myCaches[myLastCacheInd]->BuildCache(myDegree, myPeriodic, aFlatKnots, myDegree + 1, myPoles, myWeights); +} + +template +BSplCLib_MultiSpanCacheBase::BSplCLib_MultiSpanCacheBase( + const Standard_Integer theDegree, + const Standard_Boolean thePeriodic, + const TColStd_Array1OfReal* theKnots, + const TColStd_Array1OfInteger* theMults, + const TColStd_Array1OfReal* theFlatKnots, + const Array1OfPOINT& thePoles, + const TColStd_Array1OfReal* theWeights) + : myDegree(theDegree), + myPeriodic(thePeriodic), + myFirstKnot(theKnots->First()), + myLastKnot(theKnots->Last()), + myKnots(theKnots), + myMults(theMults), + myFlatKnots(theFlatKnots), + myPoles(thePoles), + myWeights(theWeights), + mySingleSpan(theKnots->Length() == 2), + myCaches(theKnots->Upper() - theKnots->Lower()), + myLastCacheInd(0) +{ +} + +template +BSplCLib_MultiSpanCacheBase::~BSplCLib_MultiSpanCacheBase() +{ + Standard_Integer aSize = (Standard_Integer)myCaches.Size(); + for (Standard_Integer i = 0; i < aSize; ++i) + myCaches[i].Nullify(); +} + +template +void BSplCLib_MultiSpanCacheBase::D0(const Standard_Real theParameter, + POINT_TYPE& thePoint) +{ + Standard_Real aPar = theParameter; + const Handle(BSplCLib_Cache)& aCache = FindCache(aPar); + aCache->D0(aPar, thePoint); +} + +template +void BSplCLib_MultiSpanCacheBase::D1(const Standard_Real theParameter, + POINT_TYPE& thePoint, + VEC_TYPE& theTangent) +{ + Standard_Real aPar = theParameter; + const Handle(BSplCLib_Cache)& aCache = FindCache(aPar); + aCache->D1(aPar, thePoint, theTangent); +} + +template +void BSplCLib_MultiSpanCacheBase::D2(const Standard_Real theParameter, + POINT_TYPE& thePoint, + VEC_TYPE& theTangent, + VEC_TYPE& theCurvature) +{ + Standard_Real aPar = theParameter; + const Handle(BSplCLib_Cache)& aCache = FindCache(aPar); + aCache->D2(aPar, thePoint, theTangent, theCurvature); +} + +template +void BSplCLib_MultiSpanCacheBase::D3(const Standard_Real theParameter, + POINT_TYPE& thePoint, + VEC_TYPE& theTangent, + VEC_TYPE& theCurvature, + VEC_TYPE& theTorsion) +{ + Standard_Real aPar = theParameter; + const Handle(BSplCLib_Cache)& aCache = FindCache(aPar); + aCache->D3(aPar, thePoint, theTangent, theCurvature, theTorsion); +} + +template +Standard_Integer BSplCLib_MultiSpanCacheBase::SpanIndex(const Standard_Real theParameter) const +{ + if (mySingleSpan) + return 1; + + // Get index of a span + Standard_Integer aSpanIndex = 0; + Standard_Real aNewPar = theParameter; // unused parameter, because theParameter is already in period + BSplCLib::LocateParameter(myDegree, *myKnots, myMults, theParameter, myPeriodic, + aSpanIndex, aNewPar); + return aSpanIndex; +} + +template +const Handle(BSplCLib_Cache)& +BSplCLib_MultiSpanCacheBase::FindCache(Standard_Real& theParameter) +{ + // Normalize the parameters for periodical B-splines + if (myPeriodic && (theParameter > myLastKnot || theParameter < myFirstKnot)) + theParameter = ElCLib::InPeriod(theParameter, myFirstKnot, myLastKnot); + + // Do not want to use LocateParameter due to lack of performance. + // Just check the last used cache is valid for the given parameter. + if (!myCaches[myLastCacheInd].IsNull() && + (mySingleSpan || myCaches[myLastCacheInd]->IsCacheValid(theParameter))) + return myCaches[myLastCacheInd]; + + Standard_Integer aSpanIndex = SpanIndex(theParameter); + myLastCacheInd = aSpanIndex - (myKnots ? myKnots->Lower() : 1); + // check the cache is already built + Handle(BSplCLib_Cache)& aCache = myCaches[myLastCacheInd]; + if (aCache.IsNull()) + { + // calculate index of cache for the flat knots + aSpanIndex = BSplCLib::FlatIndex(myDegree, aSpanIndex, *myMults, myPeriodic); + // build new cache + aCache = new BSplCLib_Cache; + aCache->BuildCache(myDegree, myPeriodic, *myFlatKnots, aSpanIndex, myPoles, myWeights); + } + + return aCache; +} diff --git a/src/BSplCLib/BSplCLib_MultiSpanCache.hxx b/src/BSplCLib/BSplCLib_MultiSpanCache.hxx new file mode 100644 index 0000000000..c6d39c2a59 --- /dev/null +++ b/src/BSplCLib/BSplCLib_MultiSpanCache.hxx @@ -0,0 +1,190 @@ +// Copyright (c) 2016 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _BSplCLib_MultiSpanCache_Headerfile +#define _BSplCLib_MultiSpanCache_Headerfile + +#include +#include +#include + +//! \brief Base container for list of caches for Bezier and B-spline curves. +//! +//! Applicable template arguments: +//! * POINT_TYPE = gp_Pnt2d and VEC_TYPE = gp_Vec2d +//! * POINT_TYPE = gp_Pnt and VEC_TYPE = gp_Vec +template +class BSplCLib_MultiSpanCacheBase +{ + typedef NCollection_Array1 Array1OfPOINT; + +public: + //! Construct cache for Bezier curve with given parameters + //! \param theDegree [in] degree of the curve + //! \param thePeriodic [in] periodicity of the curve + //! \param thePoles [in] array of poles of the curve + //! \param theWeights [in] array of weights of corresponding poles + //! \param theMaxSpans [in] maximal spans to be cached + BSplCLib_MultiSpanCacheBase(const Standard_Integer theDegree, + const Standard_Boolean thePeriodic, + const Array1OfPOINT& thePoles, + const TColStd_Array1OfReal* theWeights = NULL); + + //! Construct multi-span cache for B-spline curve with given parameters + //! \param theDegree [in] degree of the curve + //! \param thePeriodic [in] periodicity of the curve + //! \param theKnots [in] knots of the curve + //! \param theMults [in] multiplicities + //! \param theFlatKnots [in] knots of the curve (with repetition) + //! \param thePoles [in] array of poles of the curve + //! \param theWeights [in] array of weights of corresponding poles + //! \param theMaxSpans [in] maximal spans to be cached + BSplCLib_MultiSpanCacheBase(const Standard_Integer theDegree, + const Standard_Boolean thePeriodic, + const TColStd_Array1OfReal* theKnots, + const TColStd_Array1OfInteger* theMults, + const TColStd_Array1OfReal* theFlatKnots, + const Array1OfPOINT& thePoles, + const TColStd_Array1OfReal* theWeights = NULL); + + virtual ~BSplCLib_MultiSpanCacheBase(); + + //! Calculates the point on the curve for specified parameters + //! \param theParameter [in] parameter on the curve + //! \param thePoint [out] the result of calculation (the point on the curve) + Standard_EXPORT void D0(const Standard_Real theParameter, POINT_TYPE& thePoint); + + //! Calculates the point on the curve and its first derivative + //! \param theParameter [in] parameter on the curve + //! \param thePoint [out] the result of calculation (the point on the curve) + //! \param theTangent [out] tangent vector in the calculated point + Standard_EXPORT void D1(const Standard_Real theParameter, + POINT_TYPE& thePoint, + VEC_TYPE& theTangent); + + //! Calculates the point on the curve and derivatives till second order + //! \param theParameter [in] parameter on the curve + //! \param thePoint [out] the result of calculation (the point on the curve) + //! \param theTangent [out] tangent vector in the calculated point + //! \param theCurvature [out] curvature vector (2nd derivative) + Standard_EXPORT void D2(const Standard_Real theParameter, + POINT_TYPE& thePoint, + VEC_TYPE& theTangent, + VEC_TYPE& theCurvature); + + //! Calculates the point on the curve and three derivatives in the specified parameter + //! \param theParameter [in] parameter on the curve + //! \param thePoint [out] the result of calculation (the point on the curve) + //! \param theTangent [out] tangent vector (1st derivative) in the calculated point + //! \param theCurvature [out] curvature vector (2nd derivative) + //! \param theTorsion [out] second curvature vector (3rd derivative) + Standard_EXPORT void D3(const Standard_Real theParameter, + POINT_TYPE& thePoint, + VEC_TYPE& theTangent, + VEC_TYPE& theCurvature, + VEC_TYPE& theTorsion); + +private: + //! Calculate an index of a span by the parameter on the curve. + //! \param theParameter [in] parameter on the curve + //! \return Index of the span, used to store cache in the map. + Standard_Integer SpanIndex(const Standard_Real theParameter) const; + + //! Find cached span containing given parameter. + //! Parameter is adjusted to period for periodic curves. + //! If such span is not cached yet, prepares new cache object. + const Handle(BSplCLib_Cache)& FindCache(Standard_Real& theParameter); + + BSplCLib_MultiSpanCacheBase(const BSplCLib_MultiSpanCacheBase&); + const BSplCLib_MultiSpanCacheBase& operator=(const BSplCLib_MultiSpanCacheBase&); + +private: + typedef NCollection_LocalArray CacheArray; + + Standard_Integer myDegree; ///< degree of the curve + Standard_Boolean myPeriodic; ///< periodicity of the curve + Standard_Real myFirstKnot; ///< value of the first knot (used for periodic normalization) + Standard_Real myLastKnot; ///< value of the lsst knot (used for periodic normalization) + const TColStd_Array1OfReal* myKnots; ///< knots + const TColStd_Array1OfInteger* myMults; ///< multiplicities + const TColStd_Array1OfReal* myFlatKnots; ///< knots duplicated according to multiplicity + const Array1OfPOINT& myPoles; ///< array of poles + const TColStd_Array1OfReal* myWeights; ///< array of weights + + CacheArray myCaches; ///< array of caches + Standard_Integer myLastCacheInd; ///< index of last used cache + + Standard_Boolean mySingleSpan; ///< the curve consists of just one span +}; + + +//! \brief A container for list of caches for 2D Bezier and B-spline curves. +class BSplCLib_MultiSpanCache2D : public BSplCLib_MultiSpanCacheBase, public Standard_Transient +{ +public: + Standard_EXPORT BSplCLib_MultiSpanCache2D(const Standard_Integer theDegree, + const Standard_Boolean thePeriodic, + const TColgp_Array1OfPnt2d& thePoles, + const TColStd_Array1OfReal* theWeights = NULL) + : BSplCLib_MultiSpanCacheBase(theDegree, thePeriodic, thePoles, theWeights) + { + } + + Standard_EXPORT BSplCLib_MultiSpanCache2D(const Standard_Integer theDegree, + const Standard_Boolean thePeriodic, + const TColStd_Array1OfReal* theKnots, + const TColStd_Array1OfInteger* theMults, + const TColStd_Array1OfReal* theFlatKnots, + const TColgp_Array1OfPnt2d& thePoles, + const TColStd_Array1OfReal* theWeights = NULL) + : BSplCLib_MultiSpanCacheBase(theDegree, thePeriodic, theKnots, theMults, + theFlatKnots, thePoles, theWeights) + { + } + + DEFINE_STANDARD_RTTI_INLINE(BSplCLib_MultiSpanCache2D, Standard_Transient) +}; + +//! \brief A container for list of caches for 3D Bezier and B-spline curves. +class BSplCLib_MultiSpanCache3D : public BSplCLib_MultiSpanCacheBase, public Standard_Transient +{ +public: + Standard_EXPORT BSplCLib_MultiSpanCache3D(const Standard_Integer theDegree, + const Standard_Boolean thePeriodic, + const TColgp_Array1OfPnt& thePoles, + const TColStd_Array1OfReal* theWeights = NULL) + : BSplCLib_MultiSpanCacheBase(theDegree, thePeriodic, thePoles, theWeights) + { + } + + Standard_EXPORT BSplCLib_MultiSpanCache3D(const Standard_Integer theDegree, + const Standard_Boolean thePeriodic, + const TColStd_Array1OfReal* theKnots, + const TColStd_Array1OfInteger* theMults, + const TColStd_Array1OfReal* theFlatKnots, + const TColgp_Array1OfPnt& thePoles, + const TColStd_Array1OfReal* theWeights = NULL) + : BSplCLib_MultiSpanCacheBase(theDegree, thePeriodic, theKnots, theMults, + theFlatKnots, thePoles, theWeights) + { + } + + DEFINE_STANDARD_RTTI_INLINE(BSplCLib_MultiSpanCache3D, Standard_Transient) +}; + +DEFINE_STANDARD_HANDLE(BSplCLib_MultiSpanCache2D, Standard_Transient) +DEFINE_STANDARD_HANDLE(BSplCLib_MultiSpanCache3D, Standard_Transient) + +#include + +#endif diff --git a/src/BSplCLib/FILES b/src/BSplCLib/FILES index 2975ef6145..b5f81d4281 100755 --- a/src/BSplCLib/FILES +++ b/src/BSplCLib/FILES @@ -11,3 +11,5 @@ BSplCLib_CurveComputation.gxx BSplCLib_EvaluatorFunction.hxx BSplCLib_KnotDistribution.hxx BSplCLib_MultDistribution.hxx +BSplCLib_MultiSpanCache.gxx +BSplCLib_MultiSpanCache.hxx diff --git a/src/BSplSLib/BSplSLib_Cache.cxx b/src/BSplSLib/BSplSLib_Cache.cxx index dd9ba2eaac..eb52c0532c 100644 --- a/src/BSplSLib/BSplSLib_Cache.cxx +++ b/src/BSplSLib/BSplSLib_Cache.cxx @@ -33,107 +33,41 @@ static Standard_Real* ConvertArray(const Handle(TColStd_HArray2OfReal)& theHArra BSplSLib_Cache::BSplSLib_Cache() + : myIsRational(Standard_False) { - myPolesWeights.Nullify(); - myIsRational = Standard_False; - mySpanStart[0] = mySpanStart[1] = 0.0; + mySpanStart[0] = mySpanStart[1] = 0.0; mySpanLength[0] = mySpanLength[1] = 0.0; - mySpanIndex[0] = mySpanIndex[1] = 0; - myDegree[0] = myDegree[1] = 0; - myFlatKnots[0].Nullify(); - myFlatKnots[1].Nullify(); -} - -BSplSLib_Cache::BSplSLib_Cache(const Standard_Integer& theDegreeU, - const Standard_Boolean& thePeriodicU, - const TColStd_Array1OfReal& theFlatKnotsU, - const Standard_Integer& theDegreeV, - const Standard_Boolean& thePeriodicV, - const TColStd_Array1OfReal& theFlatKnotsV, - const TColgp_Array2OfPnt& thePoles, - const TColStd_Array2OfReal* theWeights) -{ - Standard_Real aU = theFlatKnotsU.Value(theFlatKnotsU.Lower() + theDegreeU); - Standard_Real aV = theFlatKnotsV.Value(theFlatKnotsV.Lower() + theDegreeV); - - BuildCache(aU, aV, - theDegreeU, thePeriodicU, theFlatKnotsU, - theDegreeV, thePeriodicV, theFlatKnotsV, - thePoles, theWeights); + mySpanLengthRec[0] = mySpanLengthRec[1] = 0.0; + mySpanIndex[0] = mySpanIndex[1] = 0; + mySpanIndexMin[0] = mySpanIndexMin[1] = 0; + mySpanIndexMax[0] = mySpanIndexMax[1] = 0; + myDegree[0] = myDegree[1] = 0; } Standard_Boolean BSplSLib_Cache::IsCacheValid(Standard_Real theParameterU, Standard_Real theParameterV) const { - Standard_Real aNewU = theParameterU; - Standard_Real aNewV = theParameterV; - if (!myFlatKnots[0].IsNull()) - PeriodicNormalization(myDegree[0], myFlatKnots[0]->Array1(), aNewU); - if (!myFlatKnots[1].IsNull()) - PeriodicNormalization(myDegree[1], myFlatKnots[1]->Array1(), aNewV); - - Standard_Real aDelta0 = aNewU - mySpanStart[0]; - Standard_Real aDelta1 = aNewV - mySpanStart[1]; + Standard_Real aDelta0 = theParameterU - mySpanStart[0]; + Standard_Real aDelta1 = theParameterV - mySpanStart[1]; return ((aDelta0 >= -mySpanLength[0] || mySpanIndex[0] == mySpanIndexMin[0]) && - (aDelta0 < mySpanLength[0] || mySpanIndex[0] == mySpanIndexMax[0]) && + (aDelta0 < mySpanLength[0] || mySpanIndex[0] == mySpanIndexMax[0]) && (aDelta1 >= -mySpanLength[1] || mySpanIndex[1] == mySpanIndexMin[1]) && - (aDelta1 < mySpanLength[1] || mySpanIndex[1] == mySpanIndexMax[1])); -} - -void BSplSLib_Cache::PeriodicNormalization(const Standard_Integer& theDegree, - const TColStd_Array1OfReal& theFlatKnots, - Standard_Real& theParameter) const -{ - Standard_Real aPeriod = theFlatKnots.Value(theFlatKnots.Upper() - theDegree) - - theFlatKnots.Value(theDegree + 1) ; - if (theParameter < theFlatKnots.Value(theDegree + 1)) - { - Standard_Real aScale = IntegerPart( - (theFlatKnots.Value(theDegree + 1) - theParameter) / aPeriod); - theParameter += aPeriod * (aScale + 1.0); - } - if (theParameter > theFlatKnots.Value(theFlatKnots.Upper() - theDegree)) - { - Standard_Real aScale = IntegerPart( - (theParameter - theFlatKnots.Value(theFlatKnots.Upper() - theDegree)) / aPeriod); - theParameter -= aPeriod * (aScale + 1.0); - } + (aDelta1 < mySpanLength[1] || mySpanIndex[1] == mySpanIndexMax[1])); } -void BSplSLib_Cache::BuildCache(const Standard_Real& theParameterU, - const Standard_Real& theParameterV, - const Standard_Integer& theDegreeU, - const Standard_Boolean& thePeriodicU, - const TColStd_Array1OfReal& theFlatKnotsU, - const Standard_Integer& theDegreeV, - const Standard_Boolean& thePeriodicV, - const TColStd_Array1OfReal& theFlatKnotsV, - const TColgp_Array2OfPnt& thePoles, - const TColStd_Array2OfReal* theWeights) +void BSplSLib_Cache::BuildCache(const Standard_Integer theDegreeU, + const Standard_Boolean thePeriodicU, + const TColStd_Array1OfReal& theFlatKnotsU, + const Standard_Integer theCachedSpanU, + const Standard_Integer theDegreeV, + const Standard_Boolean thePeriodicV, + const TColStd_Array1OfReal& theFlatKnotsV, + const Standard_Integer theCachedSpanV, + const TColgp_Array2OfPnt& thePoles, + const TColStd_Array2OfReal* theWeights) { - // Normalize the parameters for periodical B-splines - Standard_Real aNewParamU = theParameterU; - if (thePeriodicU) - { - PeriodicNormalization(theDegreeU, theFlatKnotsU, aNewParamU); - myFlatKnots[0] = new TColStd_HArray1OfReal(1, theFlatKnotsU.Length()); - myFlatKnots[0]->ChangeArray1() = theFlatKnotsU; - } - else if (!myFlatKnots[0].IsNull()) // Periodical curve became non-periodical - myFlatKnots[0].Nullify(); - - Standard_Real aNewParamV = theParameterV; - if (thePeriodicV) - { - PeriodicNormalization(theDegreeV, theFlatKnotsV, aNewParamV); - myFlatKnots[1] = new TColStd_HArray1OfReal(1, theFlatKnotsV.Length()); - myFlatKnots[1]->ChangeArray1() = theFlatKnotsV; - } - else if (!myFlatKnots[1].IsNull()) // Periodical curve became non-periodical - myFlatKnots[1].Nullify(); - Standard_Integer aMinDegree = Min(theDegreeU, theDegreeV); Standard_Integer aMaxDegree = Max(theDegreeU, theDegreeV); @@ -145,27 +79,17 @@ void BSplSLib_Cache::BuildCache(const Standard_Real& theParameterU, myDegree[0] = theDegreeU; myDegree[1] = theDegreeV; - mySpanIndex[0] = mySpanIndex[1] = 0; - BSplCLib::LocateParameter(theDegreeU, theFlatKnotsU, BSplCLib::NoMults(), aNewParamU, - thePeriodicU, mySpanIndex[0], aNewParamU); - BSplCLib::LocateParameter(theDegreeV, theFlatKnotsV, BSplCLib::NoMults(), aNewParamV, - thePeriodicV, mySpanIndex[1], aNewParamV); - - // Protection against Out of Range exception. - if (mySpanIndex[0] >= theFlatKnotsU.Length()) { - mySpanIndex[0] = theFlatKnotsU.Length() - 1; - } + mySpanIndex[0] = theCachedSpanU; + mySpanIndex[1] = theCachedSpanV; mySpanLength[0] = (theFlatKnotsU.Value(mySpanIndex[0] + 1) - theFlatKnotsU.Value(mySpanIndex[0])) * 0.5; + mySpanLengthRec[0] = 1.0 / mySpanLength[0]; mySpanStart[0] = theFlatKnotsU.Value(mySpanIndex[0]) + mySpanLength[0]; - // Protection against Out of Range exception. - if (mySpanIndex[1] >= theFlatKnotsV.Length()) { - mySpanIndex[1] = theFlatKnotsV.Length() - 1; - } - mySpanLength[1] = (theFlatKnotsV.Value(mySpanIndex[1] + 1) - theFlatKnotsV.Value(mySpanIndex[1])) * 0.5; - mySpanStart[1] = theFlatKnotsV.Value(mySpanIndex[1]) + mySpanLength[1]; + mySpanLengthRec[1] = 1.0 / mySpanLength[1]; + mySpanStart[1] = theFlatKnotsV.Value(mySpanIndex[1]) + mySpanLength[1]; + mySpanIndexMin[0] = thePeriodicU ? 0 : theDegreeU + 1; mySpanIndexMax[0] = theFlatKnotsU.Length() - 1 - theDegreeU; mySpanIndexMin[1] = thePeriodicV ? 0 : theDegreeV + 1; @@ -182,18 +106,12 @@ void BSplSLib_Cache::BuildCache(const Standard_Real& theParameterU, } -void BSplSLib_Cache::D0(const Standard_Real& theU, - const Standard_Real& theV, - gp_Pnt& thePoint) const +void BSplSLib_Cache::D0(const Standard_Real theU, + const Standard_Real theV, + gp_Pnt& thePoint) const { - Standard_Real aNewU = theU; - Standard_Real aNewV = theV; - if (!myFlatKnots[0].IsNull()) // B-spline is U-periodical - PeriodicNormalization(myDegree[0], myFlatKnots[0]->Array1(), aNewU); - aNewU = (aNewU - mySpanStart[0]) / mySpanLength[0]; - if (!myFlatKnots[1].IsNull()) // B-spline is V-periodical - PeriodicNormalization(myDegree[1], myFlatKnots[1]->Array1(), aNewV); - aNewV = (aNewV - mySpanStart[1]) / mySpanLength[1]; + Standard_Real aNewU = (theU - mySpanStart[0]) / mySpanLength[0]; + Standard_Real aNewV = (theV - mySpanStart[1]) / mySpanLength[1]; Standard_Real* aPolesArray = ConvertArray(myPolesWeights); Standard_Real aPoint[4]; @@ -232,26 +150,19 @@ void BSplSLib_Cache::D0(const Standard_Real& theU, } -void BSplSLib_Cache::D1(const Standard_Real& theU, - const Standard_Real& theV, - gp_Pnt& thePoint, - gp_Vec& theTangentU, - gp_Vec& theTangentV) const +void BSplSLib_Cache::D1(const Standard_Real theU, + const Standard_Real theV, + gp_Pnt& thePoint, + gp_Vec& theTangentU, + gp_Vec& theTangentV) const { - Standard_Real aNewU = theU; - Standard_Real aNewV = theV; - Standard_Real anInvU = 1.0 / mySpanLength[0]; - Standard_Real anInvV = 1.0 / mySpanLength[1]; - if (!myFlatKnots[0].IsNull()) // B-spline is U-periodical - PeriodicNormalization(myDegree[0], myFlatKnots[0]->Array1(), aNewU); - aNewU = (aNewU - mySpanStart[0]) * anInvU; - if (!myFlatKnots[1].IsNull()) // B-spline is V-periodical - PeriodicNormalization(myDegree[1], myFlatKnots[1]->Array1(), aNewV); - aNewV = (aNewV - mySpanStart[1]) * anInvV; + Standard_Real aNewU = (theU - mySpanStart[0]) * mySpanLengthRec[0]; + Standard_Real aNewV = (theV - mySpanStart[1]) * mySpanLengthRec[1]; Standard_Real* aPolesArray = ConvertArray(myPolesWeights); - Standard_Real aPntDeriv[16]; // result storage (point and derivative coordinates) - for (Standard_Integer i = 0; i< 16; i++) aPntDeriv[i] = 0.0; + static const Standard_Integer PNT_DERIV_LEN = 16; + Standard_Real aPntDeriv[PNT_DERIV_LEN]; // result storage (point and derivative coordinates) + memset(aPntDeriv, 0, PNT_DERIV_LEN * sizeof(Standard_Real)); Standard_Integer aDimension = myIsRational ? 4 : 3; Standard_Integer aCacheCols = myPolesWeights->RowLength(); @@ -284,7 +195,7 @@ void BSplSLib_Cache::D1(const Standard_Real& theU, aPntDeriv[aDimension<<1]); Standard_Real* aResult = aPntDeriv; - Standard_Real aTempStorage[12]; + Standard_Real aTempStorage[PNT_DERIV_LEN]; if (myIsRational) // calculate derivatives divided by weight's derivatives { BSplSLib::RationalDerivative(1, 1, 1, 1, aPntDeriv[0], aTempStorage[0]); @@ -305,34 +216,27 @@ void BSplSLib_Cache::D1(const Standard_Real& theU, Standard_Integer aShift = aDimension<<1; theTangentV.SetCoord(aResult[aShift], aResult[aShift + 1], aResult[aShift + 2]); } - theTangentU.Multiply(anInvU); - theTangentV.Multiply(anInvV); + theTangentU.Multiply(mySpanLengthRec[0]); + theTangentV.Multiply(mySpanLengthRec[1]); } -void BSplSLib_Cache::D2(const Standard_Real& theU, - const Standard_Real& theV, - gp_Pnt& thePoint, - gp_Vec& theTangentU, - gp_Vec& theTangentV, - gp_Vec& theCurvatureU, - gp_Vec& theCurvatureV, - gp_Vec& theCurvatureUV) const +void BSplSLib_Cache::D2(const Standard_Real theU, + const Standard_Real theV, + gp_Pnt& thePoint, + gp_Vec& theTangentU, + gp_Vec& theTangentV, + gp_Vec& theCurvatureU, + gp_Vec& theCurvatureV, + gp_Vec& theCurvatureUV) const { - Standard_Real aNewU = theU; - Standard_Real aNewV = theV; - Standard_Real anInvU = 1.0 / mySpanLength[0]; - Standard_Real anInvV = 1.0 / mySpanLength[1]; - if (!myFlatKnots[0].IsNull()) // B-spline is U-periodical - PeriodicNormalization(myDegree[0], myFlatKnots[0]->Array1(), aNewU); - aNewU = (aNewU - mySpanStart[0]) * anInvU; - if (!myFlatKnots[1].IsNull()) // B-spline is V-periodical - PeriodicNormalization(myDegree[1], myFlatKnots[1]->Array1(), aNewV); - aNewV = (aNewV - mySpanStart[1]) * anInvV; + Standard_Real aNewU = (theU - mySpanStart[0]) * mySpanLengthRec[0]; + Standard_Real aNewV = (theV - mySpanStart[1]) * mySpanLengthRec[1]; Standard_Real* aPolesArray = ConvertArray(myPolesWeights); - Standard_Real aPntDeriv[36]; // result storage (point and derivative coordinates) - for (Standard_Integer i = 0; i < 36; i++) aPntDeriv[i] = 0.0; + static const Standard_Integer PNT_DERIV_LEN = 36; + Standard_Real aPntDeriv[PNT_DERIV_LEN]; // result storage (point and derivative coordinates) + memset(aPntDeriv, 0, PNT_DERIV_LEN * sizeof(Standard_Real)); Standard_Integer aDimension = myIsRational ? 4 : 3; Standard_Integer aCacheCols = myPolesWeights->RowLength(); @@ -381,7 +285,7 @@ void BSplSLib_Cache::D2(const Standard_Real& theU, aPntDeriv[6 * aDimension]); Standard_Real* aResult = aPntDeriv; - Standard_Real aTempStorage[36]; + Standard_Real aTempStorage[PNT_DERIV_LEN]; if (myIsRational) // calculate derivatives divided by weight's derivatives { BSplSLib::RationalDerivative(2, 2, 2, 2, aPntDeriv[0], aTempStorage[0]); @@ -414,10 +318,10 @@ void BSplSLib_Cache::D2(const Standard_Real& theU, aShift += (aDimension << 1); theCurvatureV.SetCoord(aResult[aShift], aResult[aShift + 1], aResult[aShift + 2]); } - theTangentU.Multiply(anInvU); - theTangentV.Multiply(anInvV); - theCurvatureU.Multiply(anInvU * anInvU); - theCurvatureV.Multiply(anInvV * anInvV); - theCurvatureUV.Multiply(anInvU * anInvV); + theTangentU.Multiply(mySpanLengthRec[0]); + theTangentV.Multiply(mySpanLengthRec[1]); + theCurvatureU.Multiply(mySpanLengthRec[0] * mySpanLengthRec[0]); + theCurvatureV.Multiply(mySpanLengthRec[1] * mySpanLengthRec[1]); + theCurvatureUV.Multiply(mySpanLengthRec[0] * mySpanLengthRec[1]); } diff --git a/src/BSplSLib/BSplSLib_Cache.hxx b/src/BSplSLib/BSplSLib_Cache.hxx index 821cf7e1f4..f81b1407cf 100644 --- a/src/BSplSLib/BSplSLib_Cache.hxx +++ b/src/BSplSLib/BSplSLib_Cache.hxx @@ -38,23 +38,6 @@ class BSplSLib_Cache : public Standard_Transient public: //! Default constructor Standard_EXPORT BSplSLib_Cache(); - //! Constructor for caching of the span for the surface - //! \param theDegreeU degree along the first parameter (U) of the surface - //! \param thePeriodicU identify the surface is periodical along U axis - //! \param theFlatKnotsU knots of the surface (with repetition) along U axis - //! \param theDegreeV degree alogn the second parameter (V) of the surface - //! \param thePeriodicV identify the surface is periodical along V axis - //! \param theFlatKnotsV knots of the surface (with repetition) along V axis - //! \param thePoles array of poles of the surface - //! \param theWeights array of weights of corresponding poles - Standard_EXPORT BSplSLib_Cache(const Standard_Integer& theDegreeU, - const Standard_Boolean& thePeriodicU, - const TColStd_Array1OfReal& theFlatKnotsU, - const Standard_Integer& theDegreeV, - const Standard_Boolean& thePeriodicV, - const TColStd_Array1OfReal& theFlatKnotsV, - const TColgp_Array2OfPnt& thePoles, - const TColStd_Array2OfReal* theWeights = NULL); //! Verifies validity of the cache using parameters of the point //! \param theParameterU first parameter of the point placed in the span @@ -63,32 +46,32 @@ public: Standard_Real theParameterV) const; //! Recomputes the cache data. Does not verify validity of the cache - //! \param theParameterU the parametric value on the U axis to identify the span - //! \param theParameterV the parametric value on the V axis to identify the span //! \param theDegreeU degree along U axis //! \param thePeriodicU identify whether the surface is periodic along U axis //! \param theFlatKnotsU flat knots of the surface along U axis + //! \param theCachedSpanU index along U axis of span to be cached //! \param theDegreeV degree along V axis //! \param thePeriodicV identify whether the surface is periodic along V axis //! \param theFlatKnotsV flat knots of the surface along V axis + //! \param theCachedSpanV index along V axis of span to be cached //! \param thePoles array of poles of the surface //! \param theWeights array of weights of corresponding poles - Standard_EXPORT void BuildCache(const Standard_Real& theParameterU, - const Standard_Real& theParameterV, - const Standard_Integer& theDegreeU, - const Standard_Boolean& thePeriodicU, - const TColStd_Array1OfReal& theFlatKnotsU, - const Standard_Integer& theDegreeV, - const Standard_Boolean& thePeriodicV, - const TColStd_Array1OfReal& theFlatKnotsV, - const TColgp_Array2OfPnt& thePoles, - const TColStd_Array2OfReal* theWeights = NULL); + Standard_EXPORT void BuildCache(const Standard_Integer theDegreeU, + const Standard_Boolean thePeriodicU, + const TColStd_Array1OfReal& theFlatKnotsU, + const Standard_Integer theCachedSpanU, + const Standard_Integer theDegreeV, + const Standard_Boolean thePeriodicV, + const TColStd_Array1OfReal& theFlatKnotsV, + const Standard_Integer theCachedSpanV, + const TColgp_Array2OfPnt& thePoles, + const TColStd_Array2OfReal* theWeights = NULL); //! Calculates the point on the surface for specified parameters //! \param[in] theU first parameter for calculation of the value //! \param[in] theV second parameter for calculation of the value //! \param[out] thePoint the result of calculation (the point on the surface) - Standard_EXPORT void D0(const Standard_Real& theU, const Standard_Real& theV, gp_Pnt& thePoint) const; + Standard_EXPORT void D0(const Standard_Real theU, const Standard_Real theV, gp_Pnt& thePoint) const; //! Calculates the point on the surface and its first derivative //! \param[in] theU first parameter of calculation of the value @@ -96,11 +79,11 @@ public: //! \param[out] thePoint the result of calculation (the point on the surface) //! \param[out] theTangentU tangent vector along U axis in the calculated point //! \param[out] theTangentV tangent vector along V axis in the calculated point - Standard_EXPORT void D1(const Standard_Real& theU, - const Standard_Real& theV, - gp_Pnt& thePoint, - gp_Vec& theTangentU, - gp_Vec& theTangentV) const; + Standard_EXPORT void D1(const Standard_Real theU, + const Standard_Real theV, + gp_Pnt& thePoint, + gp_Vec& theTangentU, + gp_Vec& theTangentV) const; //! Calculates the point on the surface and derivatives till second order //! \param[in] theU first parameter of calculation of the value @@ -111,27 +94,18 @@ public: //! \param[out] theCurvatureU curvature vector (2nd derivative on U) along U axis //! \param[out] theCurvatureV curvature vector (2nd derivative on V) along V axis //! \param[out] theCurvatureUV 2nd mixed derivative on U anv V - Standard_EXPORT void D2(const Standard_Real& theU, - const Standard_Real& theV, - gp_Pnt& thePoint, - gp_Vec& theTangentU, - gp_Vec& theTangentV, - gp_Vec& theCurvatureU, - gp_Vec& theCurvatureV, - gp_Vec& theCurvatureUV) const; + Standard_EXPORT void D2(const Standard_Real theU, + const Standard_Real theV, + gp_Pnt& thePoint, + gp_Vec& theTangentU, + gp_Vec& theTangentV, + gp_Vec& theCurvatureU, + gp_Vec& theCurvatureV, + gp_Vec& theCurvatureUV) const; DEFINE_STANDARD_RTTIEXT(BSplSLib_Cache,Standard_Transient) -protected: - //! Normalizes the parameter for periodical surfaces - //! \param[in] theDegree degree along selected direction - //! \param[in] theFlatKnots knots with repetitions along selected direction - //! \param[in,out] theParameter the value to be normalized into the knots array - void PeriodicNormalization(const Standard_Integer& theDegree, - const TColStd_Array1OfReal& theFlatKnots, - Standard_Real& theParameter) const; - private: Handle(TColStd_HArray2OfReal) myPolesWeights; ///< array of poles and weights of calculated cache // the array has following structure: @@ -140,15 +114,14 @@ private: // for non-rational surfaces there is no weight; // size of array: (max(myDegree)+1) * A*(min(myDegree)+1), where A = 4 or 3 - Standard_Boolean myIsRational; ///< identifies the rationality of Bezier/B-spline surface - Standard_Real mySpanStart[2]; ///< parameters (u, v) for the frst point of the span - Standard_Real mySpanLength[2]; ///< lengths of the span along corresponding parameter - Standard_Integer mySpanIndex[2]; ///< indexes of the span on Bezier/B-spline surface - Standard_Integer mySpanIndexMin[2]; ///< minimal indexes of span - Standard_Integer mySpanIndexMax[2]; ///< maximal indexes of span - Standard_Integer myDegree[2]; ///< degrees of Bezier/B-spline for each parameter - Handle(TColStd_HArray1OfReal) myFlatKnots[2]; ///< arrays of knots of Bezier/B-spline - // (used for periodic normalization of parameters, Null for non-periodical splines) + Standard_Boolean myIsRational; ///< identifies the rationality of Bezier/B-spline surface + Standard_Real mySpanStart[2]; ///< parameters (u, v) for the frst point of the span + Standard_Real mySpanLength[2]; ///< lengths of the span along corresponding parameter + Standard_Real mySpanLengthRec[2]; ///< reciprocal values for the span lengths (mySpanLengthRec[i] = 1/mySpanLength[i]) + Standard_Integer mySpanIndex[2]; ///< indexes of the span on Bezier/B-spline surface + Standard_Integer mySpanIndexMin[2]; ///< minimal indexes of span + Standard_Integer mySpanIndexMax[2]; ///< maximal indexes of span + Standard_Integer myDegree[2]; ///< degrees of Bezier/B-spline for each parameter }; DEFINE_STANDARD_HANDLE(BSplSLib_Cache, Standard_Transient) diff --git a/src/BSplSLib/BSplSLib_MultiSpanCache.cxx b/src/BSplSLib/BSplSLib_MultiSpanCache.cxx new file mode 100644 index 0000000000..4e50ef06a4 --- /dev/null +++ b/src/BSplSLib/BSplSLib_MultiSpanCache.cxx @@ -0,0 +1,235 @@ +// Copyright (c) 2014 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include +#include + +BSplSLib_MultiSpanCache::BSplSLib_MultiSpanCache(const Standard_Integer theDegreeU, + const Standard_Boolean thePeriodicU, + const Standard_Integer theDegreeV, + const Standard_Boolean thePeriodicV, + const TColgp_Array2OfPnt& thePoles, + const TColStd_Array2OfReal* theWeights) + : myDegreeU(theDegreeU), + myDegreeV(theDegreeV), + myPeriodicU(thePeriodicU), + myPeriodicV(thePeriodicV), + myKnotsU(NULL), + myKnotsV(NULL), + myMultsU(NULL), + myMultsV(NULL), + myFlatKnotsU(NULL), + myFlatKnotsV(NULL), + myFirstKnotU(0.), + myFirstKnotV(0.), + myLastKnotU(1.), + myLastKnotV(1.), + myPoles(thePoles), + myWeights(theWeights), + mySingleSpanU(1), + mySingleSpanV(1), + myCaches(1) +{ + Clear(); + + // Build cache for single span + TColStd_Array1OfReal aFlatKnotsU(BSplCLib::FlatBezierKnots(myDegreeU), 1, (myDegreeU + 1) * 2); + TColStd_Array1OfReal aFlatKnotsV(BSplCLib::FlatBezierKnots(myDegreeV), 1, (myDegreeV + 1) * 2); + myCaches[myLastCacheInd] = new BSplSLib_Cache; + myCaches[myLastCacheInd]->BuildCache(myDegreeU, myPeriodicU, aFlatKnotsU, myDegreeU + 1, + myDegreeV, myPeriodicV, aFlatKnotsV, myDegreeV + 1, + myPoles, myWeights); +} + +BSplSLib_MultiSpanCache::BSplSLib_MultiSpanCache(const Standard_Integer theDegreeU, + const Standard_Boolean thePeriodicU, + const TColStd_Array1OfReal* theKnotsU, + const TColStd_Array1OfInteger* theMultsU, + const TColStd_Array1OfReal* theFlatKnotsU, + const Standard_Integer theDegreeV, + const Standard_Boolean thePeriodicV, + const TColStd_Array1OfReal* theKnotsV, + const TColStd_Array1OfInteger* theMultsV, + const TColStd_Array1OfReal* theFlatKnotsV, + const TColgp_Array2OfPnt& thePoles, + const TColStd_Array2OfReal* theWeights) + : myDegreeU(theDegreeU), + myDegreeV(theDegreeV), + myPeriodicU(thePeriodicU), + myPeriodicV(thePeriodicV), + myKnotsU(theKnotsU), + myKnotsV(theKnotsV), + myMultsU(theMultsU), + myMultsV(theMultsV), + myFlatKnotsU(theFlatKnotsU), + myFlatKnotsV(theFlatKnotsV), + myFirstKnotU(theKnotsU->First()), + myFirstKnotV(theKnotsV->First()), + myLastKnotU(theKnotsU->Last()), + myLastKnotV(theKnotsV->Last()), + myPoles(thePoles), + myWeights(theWeights), + mySingleSpanU(0), + mySingleSpanV(0), + myCaches((theKnotsU->Upper() - theKnotsU->Lower()) * (theKnotsV->Upper() - theKnotsV->Lower())) +{ + Clear(); + + Standard_Boolean isSingleSpanU = myKnotsU->Length() == 2; + Standard_Boolean isSingleSpanV = myKnotsV->Length() == 2; + + // Check the surface has one span at all + if (isSingleSpanU || isSingleSpanV) + { + Standard_Integer aSpanIndex; // works as temporary index if surface has more than one span + Standard_Real aTempU = myKnotsU->First(); + Standard_Real aTempV = myKnotsV->First(); + SpanIndex(aTempU, aTempV, + isSingleSpanU ? mySingleSpanU : aSpanIndex, + isSingleSpanV ? mySingleSpanV : aSpanIndex); + } +} + +BSplSLib_MultiSpanCache::~BSplSLib_MultiSpanCache() +{ + Standard_Integer aSize = (Standard_Integer)myCaches.Size(); + for (Standard_Integer i = 0; i < aSize; ++i) + myCaches[i].Nullify(); +} + +void BSplSLib_MultiSpanCache::Clear() +{ + myLastCacheInd = 0; + myLastU.myParameter = Precision::Infinite(); + myLastU.mySpan = -1; + myLastV.myParameter = Precision::Infinite(); + myLastV.mySpan = -1; +} + +void BSplSLib_MultiSpanCache::D0(const Standard_Real theU, + const Standard_Real theV, + gp_Pnt& thePoint) +{ + Standard_Real aU = theU; + Standard_Real aV = theV; + const Handle(BSplSLib_Cache)& aCache = FindCache(aU, aV); + aCache->D0(aU, aV, thePoint); +} + +void BSplSLib_MultiSpanCache::D1(const Standard_Real theU, + const Standard_Real theV, + gp_Pnt& thePoint, + gp_Vec& theTangentU, + gp_Vec& theTangentV) +{ + Standard_Real aU = theU; + Standard_Real aV = theV; + const Handle(BSplSLib_Cache)& aCache = FindCache(aU, aV); + aCache->D1(aU, aV, thePoint, theTangentU, theTangentV); +} + +void BSplSLib_MultiSpanCache::D2(const Standard_Real theU, + const Standard_Real theV, + gp_Pnt& thePoint, + gp_Vec& theTangentU, + gp_Vec& theTangentV, + gp_Vec& theCurvatureU, + gp_Vec& theCurvatureV, + gp_Vec& theCurvatureUV) +{ + Standard_Real aU = theU; + Standard_Real aV = theV; + const Handle(BSplSLib_Cache)& aCache = FindCache(aU, aV); + aCache->D2(aU, aV, thePoint, theTangentU, theTangentV, + theCurvatureU, theCurvatureV, theCurvatureUV); +} + +Standard_Integer BSplSLib_MultiSpanCache::SpanIndex(const Standard_Real theU, + const Standard_Real theV, + Standard_Integer& theSpanIndexU, + Standard_Integer& theSpanIndexV) const +{ + // Get indices along each parameter (U, V) + theSpanIndexU = mySingleSpanU; + theSpanIndexV = mySingleSpanV; + if (IsSingleSpan()) + return 0; + + if (theSpanIndexU == 0) + { + if (theU == myLastU.myParameter) // the parameters should be equal to a bit + theSpanIndexU = myLastU.mySpan; + else + { + Standard_Real aNewU = theU; // unused parameter, because theU is already in period + BSplCLib::LocateParameter(myDegreeU, *myKnotsU, myMultsU, theU, myPeriodicU, + theSpanIndexU, aNewU); + } + } + if (theSpanIndexV == 0) + { + if (theV == myLastV.myParameter) // the parameters should be equal to a bit + theSpanIndexV = myLastV.mySpan; + else + { + Standard_Real aNewV = theV; // unused parameter, because theV is already in period + BSplCLib::LocateParameter(myDegreeV, *myKnotsV, myMultsV, theV, myPeriodicV, + theSpanIndexV, aNewV); + } + } + return (theSpanIndexU - myKnotsU->Lower()) * (myKnotsV->Upper() - myKnotsV->Lower()) + + theSpanIndexV - myKnotsV->Lower(); +} + +const Handle(BSplSLib_Cache)& BSplSLib_MultiSpanCache::FindCache(Standard_Real& theU, Standard_Real& theV) +{ + // Normalize the parameters for periodical B-splines + if (myPeriodicU && (theU > myLastKnotU || theU < myFirstKnotU)) + theU = ElCLib::InPeriod(theU, myFirstKnotU, myLastKnotU); + if (myPeriodicV && (theV > myLastKnotV || theV < myFirstKnotV)) + theV = ElCLib::InPeriod(theV, myFirstKnotV, myLastKnotV); + + // Do not want to search in due to lack of performance. + // Just check the last used cache is valid for the given parameters. + if (!myCaches[myLastCacheInd].IsNull() && + (IsSingleSpan() || myCaches[myLastCacheInd]->IsCacheValid(theU, theV))) + return myCaches[myLastCacheInd]; + + Standard_Integer aSpanIndexU = 0; + Standard_Integer aSpanIndexV = 0; + myLastCacheInd = SpanIndex(theU, theV, aSpanIndexU, aSpanIndexV); + // store last found indices + myLastU.myParameter = theU; + myLastU.mySpan = aSpanIndexU; + myLastV.myParameter = theV; + myLastV.mySpan = aSpanIndexV; + + // check the cache is already built + Handle(BSplSLib_Cache)& aCache = myCaches[myLastCacheInd]; + if (aCache.IsNull()) + { + // calculate index of cache for the flat knots + aSpanIndexU = BSplCLib::FlatIndex(myDegreeU, aSpanIndexU, *myMultsU, myPeriodicU); + aSpanIndexV = BSplCLib::FlatIndex(myDegreeV, aSpanIndexV, *myMultsV, myPeriodicV); + // build new cache + aCache = new BSplSLib_Cache; + aCache->BuildCache(myDegreeU, myPeriodicU, *myFlatKnotsU, aSpanIndexU, + myDegreeV, myPeriodicV, *myFlatKnotsV, aSpanIndexV, + myPoles, myWeights); + } + + return aCache; +} diff --git a/src/BSplSLib/BSplSLib_MultiSpanCache.hxx b/src/BSplSLib/BSplSLib_MultiSpanCache.hxx new file mode 100644 index 0000000000..ab6b759156 --- /dev/null +++ b/src/BSplSLib/BSplSLib_MultiSpanCache.hxx @@ -0,0 +1,171 @@ +// Copyright (c) 2016 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _BSplSLib_MultiSpanCache_Headerfile +#define _BSplSLib_MultiSpanCache_Headerfile + +#include +#include + +//! \brief A container for list of caches for Bezier and B-spline surfaces. +//! Stores a 2D array of caches. Each cache is initialized in first time called. +class BSplSLib_MultiSpanCache : public Standard_Transient +{ +public: + //! Construct cache for Bezier surface with given parameters + //! \param theDegreeU [in] degree along the first parameter (U) of the surface + //! \param thePeriodicU [in] identify the surface is periodical along U axis + //! \param theDegreeV [in] degree along the second parameter (V) of the surface + //! \param thePeriodicV [in] identify the surface is periodical along V axis + //! \param thePoles [in] array of poles of the surface + //! \param theWeights [in] array of weights of corresponding poles + //! \param theMaxSpans [in] maximal spans to be cached + Standard_EXPORT BSplSLib_MultiSpanCache(const Standard_Integer theDegreeU, + const Standard_Boolean thePeriodicU, + const Standard_Integer theDegreeV, + const Standard_Boolean thePeriodicV, + const TColgp_Array2OfPnt& thePoles, + const TColStd_Array2OfReal* theWeights = NULL); + + //! Construct multi-span cache for B-spline surface with given parameters + //! \param theDegreeU [in] degree along the first parameter (U) of the surface + //! \param thePeriodicU [in] identify the surface is periodical along U axis + //! \param theKnotsU [in] knots of the surface along U axis + //! \param theMultsU [in] multiplicities of knots along U axis + //! \param theFlatKnotsU [in] knots of the surface (with repetition) along U axis + //! \param theDegreeV [in] degree alogn the second parameter (V) of the surface + //! \param thePeriodicV [in] identify the surface is periodical along V axis + //! \param theKnotsV [in] knots of the surface along V axis + //! \param theMultsV [in] multiplicities of knots along V axis + //! \param theFlatKnotsV [in] knots of the surface (with repetition) along V axis + //! \param thePoles [in] array of poles of the surface + //! \param theWeights [in] array of weights of corresponding poles + //! \param theMaxSpans [in] maximal spans to be cached + Standard_EXPORT BSplSLib_MultiSpanCache(const Standard_Integer theDegreeU, + const Standard_Boolean thePeriodicU, + const TColStd_Array1OfReal* theKnotsU, + const TColStd_Array1OfInteger* theMultsU, + const TColStd_Array1OfReal* theFlatKnotsU, + const Standard_Integer theDegreeV, + const Standard_Boolean thePeriodicV, + const TColStd_Array1OfReal* theKnotsV, + const TColStd_Array1OfInteger* theMultsV, + const TColStd_Array1OfReal* theFlatKnotsV, + const TColgp_Array2OfPnt& thePoles, + const TColStd_Array2OfReal* theWeights = NULL); + + virtual ~BSplSLib_MultiSpanCache(); + + //! Clean all cached data + Standard_EXPORT void Clear(); + + //! Calculates the point on the surface for specified parameters + //! \param theU [in] first parameter for calculation of the value + //! \param theV [in] second parameter for calculation of the value + //! \param thePoint [out] the result of calculation (the point on the surface) + Standard_EXPORT void D0(const Standard_Real theU, const Standard_Real theV, gp_Pnt& thePoint); + + //! Calculates the point on the surface and its first derivative + //! \param theU [in] first parameter of calculation of the value + //! \param theV [in] second parameter of calculation of the value + //! \param thePoint [out] the result of calculation (the point on the surface) + //! \param theTangentU [out] tangent vector along U axis in the calculated point + //! \param theTangentV [out] tangent vector along V axis in the calculated point + Standard_EXPORT void D1(const Standard_Real theU, + const Standard_Real theV, + gp_Pnt& thePoint, + gp_Vec& theTangentU, + gp_Vec& theTangentV); + + //! Calculates the point on the surface and derivatives till second order + //! \param theU [in] first parameter of calculation of the value + //! \param theV [in] second parameter of calculation of the value + //! \param thePoint [out] the result of calculation (the point on the surface) + //! \param theTangentU [out] tangent vector along U axis in the calculated point + //! \param theTangentV [out] tangent vector along V axis in the calculated point + //! \param theCurvatureU [out] curvature vector (2nd derivative on U) along U axis + //! \param theCurvatureV [out] curvature vector (2nd derivative on V) along V axis + //! \param theCurvatureUV [out] 2nd mixed derivative on U anv V + Standard_EXPORT void D2(const Standard_Real theU, + const Standard_Real theV, + gp_Pnt& thePoint, + gp_Vec& theTangentU, + gp_Vec& theTangentV, + gp_Vec& theCurvatureU, + gp_Vec& theCurvatureV, + gp_Vec& theCurvatureUV); + + + DEFINE_STANDARD_RTTI_INLINE(BSplSLib_MultiSpanCache, Standard_Transient) + +private: + //! Calculate an index of a span by the parameters on surface + //! and corresponding span indices along each parameter. + //! \param theU [in] parameter U + //! \param theV [in] parameter V + //! \param theSpanIndexU [out] index of span containing theU parameter + //! \param theSpanIndexV [out] index of span containing theV parameter + //! \return Index of the cache in the array + Standard_Integer SpanIndex(const Standard_Real theU, + const Standard_Real theV, + Standard_Integer& theSpanIndexU, + Standard_Integer& theSpanIndexV) const; + + //! Find cached span containing parametric point (theU, theV). + //! Parameters are adjusted to period for periodic surface. + //! If such span is not cached yet, prepares new cache object. + const Handle(BSplSLib_Cache)& FindCache(Standard_Real& theU, Standard_Real& theV); + + //! Return Standard_True if the surface has just one span + Standard_Boolean IsSingleSpan() const + { return mySingleSpanU != 0 && mySingleSpanV != 0; } + + BSplSLib_MultiSpanCache(const BSplSLib_MultiSpanCache&); + const BSplSLib_MultiSpanCache& operator=(const BSplSLib_MultiSpanCache&); + +private: + typedef NCollection_LocalArray CacheArray; + + Standard_Integer myDegreeU; ///< degree along U + Standard_Integer myDegreeV; ///< degree along V + Standard_Boolean myPeriodicU; ///< periodicity along U + Standard_Boolean myPeriodicV; ///< periodicity along V + const TColStd_Array1OfReal* myKnotsU; ///< knots along U + const TColStd_Array1OfReal* myKnotsV; ///< knots along V + const TColStd_Array1OfInteger* myMultsU; ///< multiplicities along U + const TColStd_Array1OfInteger* myMultsV; ///< multiplicities along V + const TColStd_Array1OfReal* myFlatKnotsU; ///< knots along U (duplicated according to multiplicity) + const TColStd_Array1OfReal* myFlatKnotsV; ///< knots along V (duplicated according to multiplicity) + Standard_Real myFirstKnotU; ///< first knot along U (used for periodic normalization) + Standard_Real myLastKnotU; ///< last knot along U (used for periodic normalization) + Standard_Real myFirstKnotV; ///< first knot along V (used for periodic normalization) + Standard_Real myLastKnotV; ///< last knot along V (used for periodic normalization) + const TColgp_Array2OfPnt& myPoles; ///< array of poles + const TColStd_Array2OfReal* myWeights; ///< array of weights + + CacheArray myCaches; ///< array of caches + Standard_Integer myLastCacheInd; ///< index of last used cache + + struct { + Standard_Real myParameter; + Standard_Integer mySpan; + } myLastU, ///< last U and index of the span containing it + myLastV; ///< last V and index of the span containing it + + Standard_Integer mySingleSpanU; ///< index of the span along U, if the surface has just one span on this parameter, otherwise is 0 + Standard_Integer mySingleSpanV; ///< index of the span along V, if the surface has just one span on this parameter, otherwise is 0 +}; + +DEFINE_STANDARD_HANDLE(BSplSLib_MultiSpanCache, Standard_Transient) + +#endif diff --git a/src/BSplSLib/FILES b/src/BSplSLib/FILES index a8a96a2cb7..b7bc4db07c 100755 --- a/src/BSplSLib/FILES +++ b/src/BSplSLib/FILES @@ -5,3 +5,5 @@ BSplSLib_BzSyntaxes.cxx BSplSLib_Cache.cxx BSplSLib_Cache.hxx BSplSLib_EvaluatorFunction.hxx +BSplSLib_MultiSpanCache.cxx +BSplSLib_MultiSpanCache.hxx diff --git a/src/Geom2dAdaptor/Geom2dAdaptor_Curve.cxx b/src/Geom2dAdaptor/Geom2dAdaptor_Curve.cxx index 82cb392a03..fa7cf50f43 100644 --- a/src/Geom2dAdaptor/Geom2dAdaptor_Curve.cxx +++ b/src/Geom2dAdaptor/Geom2dAdaptor_Curve.cxx @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -182,13 +181,14 @@ void Geom2dAdaptor_Curve::load(const Handle(Geom2d_Curve)& C, myLast = ULast; myCurveCache.Nullify(); - if ( myCurve != C) { + if (myCurve != C) + { myCurve = C; myNestedEvaluator.Nullify(); myBSplineCurve.Nullify(); - Handle(Standard_Type) TheType = C->DynamicType(); - if ( TheType == STANDARD_TYPE(Geom2d_TrimmedCurve)) { + const Handle(Standard_Type)& TheType = C->DynamicType(); + if (TheType == STANDARD_TYPE(Geom2d_TrimmedCurve)) { Load(Handle(Geom2d_TrimmedCurve)::DownCast (C)->BasisCurve(), UFirst,ULast); } @@ -546,36 +546,6 @@ Standard_Real Geom2dAdaptor_Curve::Period() const return myCurve->LastParameter() - myCurve->FirstParameter(); } -//======================================================================= -//function : RebuildCache -//purpose : -//======================================================================= -void Geom2dAdaptor_Curve::RebuildCache(const Standard_Real theParameter) const -{ - if (myTypeCurve == GeomAbs_BezierCurve) - { - // Create cache for Bezier - Handle(Geom2d_BezierCurve) aBezier = Handle(Geom2d_BezierCurve)::DownCast(myCurve); - Standard_Integer aDeg = aBezier->Degree(); - TColStd_Array1OfReal aFlatKnots(BSplCLib::FlatBezierKnots(aDeg), 1, 2 * (aDeg + 1)); - if (myCurveCache.IsNull()) - myCurveCache = new BSplCLib_Cache(aDeg, aBezier->IsPeriodic(), aFlatKnots, - aBezier->Poles(), aBezier->Weights()); - myCurveCache->BuildCache(theParameter, aDeg, aBezier->IsPeriodic(), aFlatKnots, - aBezier->Poles(), aBezier->Weights()); - } - else if (myTypeCurve == GeomAbs_BSplineCurve) - { - // Create cache for B-spline - if (myCurveCache.IsNull()) - myCurveCache = new BSplCLib_Cache(myBSplineCurve->Degree(), myBSplineCurve->IsPeriodic(), - myBSplineCurve->KnotSequence(), myBSplineCurve->Poles(), myBSplineCurve->Weights()); - myCurveCache->BuildCache(theParameter, myBSplineCurve->Degree(), - myBSplineCurve->IsPeriodic(), myBSplineCurve->KnotSequence(), - myBSplineCurve->Poles(), myBSplineCurve->Weights()); - } -} - //======================================================================= //function : IsBoundary //purpose : @@ -607,6 +577,34 @@ Standard_Boolean Geom2dAdaptor_Curve::IsBoundary(const Standard_Real theU, return Standard_False; } +//======================================================================= +//function : CreateCache +//purpose : +//======================================================================= + +void Geom2dAdaptor_Curve::CreateCache() const +{ + switch (myTypeCurve) + { + case GeomAbs_BezierCurve: { + // Create cache for Bezier + Handle(Geom2d_BezierCurve) aBezier = Handle(Geom2d_BezierCurve)::DownCast(myCurve); + myCurveCache = new BSplCLib_MultiSpanCache2D(aBezier->Degree(), aBezier->IsPeriodic(), + aBezier->Poles(), aBezier->Weights()); + break; + } + case GeomAbs_BSplineCurve: + // Create cache for B-spline + myCurveCache = new BSplCLib_MultiSpanCache2D( + myBSplineCurve->Degree(), myBSplineCurve->IsPeriodic(), + &myBSplineCurve->Knots(), &myBSplineCurve->Multiplicities(), + &myBSplineCurve->KnotSequence(), myBSplineCurve->Poles(), myBSplineCurve->Weights()); + break; + default: // avoid gcc compilation warnings + break; + } +} + //======================================================================= //function : Value //purpose : @@ -633,14 +631,11 @@ void Geom2dAdaptor_Curve::D0(const Standard_Real U, gp_Pnt2d& P) const { Standard_Integer aStart = 0, aFinish = 0; if (IsBoundary(U, aStart, aFinish)) - { myBSplineCurve->LocalD0(U, aStart, aFinish, P); - } else { - // use cached data - if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U)) - RebuildCache(U); + if (myCurveCache.IsNull()) + CreateCache(); myCurveCache->D0(U, P); } break; @@ -670,14 +665,11 @@ void Geom2dAdaptor_Curve::D1(const Standard_Real U, { Standard_Integer aStart = 0, aFinish = 0; if (IsBoundary(U, aStart, aFinish)) - { myBSplineCurve->LocalD1(U, aStart, aFinish, P, V); - } else { - // use cached data - if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U)) - RebuildCache(U); + if (myCurveCache.IsNull()) + CreateCache(); myCurveCache->D1(U, P, V); } break; @@ -707,14 +699,11 @@ void Geom2dAdaptor_Curve::D2(const Standard_Real U, { Standard_Integer aStart = 0, aFinish = 0; if (IsBoundary(U, aStart, aFinish)) - { myBSplineCurve->LocalD2(U, aStart, aFinish, P, V1, V2); - } else { - // use cached data - if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U)) - RebuildCache(U); + if (myCurveCache.IsNull()) + CreateCache(); myCurveCache->D2(U, P, V1, V2); } break; @@ -745,14 +734,11 @@ void Geom2dAdaptor_Curve::D3(const Standard_Real U, { Standard_Integer aStart = 0, aFinish = 0; if (IsBoundary(U, aStart, aFinish)) - { myBSplineCurve->LocalD3(U, aStart, aFinish, P, V1, V2, V3); - } else { - // use cached data - if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U)) - RebuildCache(U); + if (myCurveCache.IsNull()) + CreateCache(); myCurveCache->D3(U, P, V1, V2, V3); } break; diff --git a/src/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx b/src/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx index 6ecbf6a5c4..0dfd760abf 100644 --- a/src/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx +++ b/src/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -187,9 +187,8 @@ private: //! Check theU relates to start or finish point of B-spline curve and return indices of span the point is located Standard_Boolean IsBoundary(const Standard_Real theU, Standard_Integer& theSpanStart, Standard_Integer& theSpanFinish) const; - //! Rebuilds B-spline cache - //! \param theParameter the value on the knot axis which identifies the caching span - void RebuildCache (const Standard_Real theParameter) const; + //! Allocates memory for a cache object + void CreateCache() const; Handle(Geom2d_Curve) myCurve; @@ -198,7 +197,7 @@ private: Standard_Real myLast; Handle(Geom2d_BSplineCurve) myBSplineCurve; ///< B-spline representation to prevent castings - mutable Handle(BSplCLib_Cache) myCurveCache; ///< Cached data for B-spline or Bezier curve + mutable Handle(BSplCLib_MultiSpanCache2D) myCurveCache; ///< Cached data for B-spline or Bezier curve Handle(Geom2dEvaluator_Curve) myNestedEvaluator; ///< Calculates value of offset curve diff --git a/src/GeomAdaptor/GeomAdaptor_Curve.cxx b/src/GeomAdaptor/GeomAdaptor_Curve.cxx index 2cb8276460..56c568cff3 100644 --- a/src/GeomAdaptor/GeomAdaptor_Curve.cxx +++ b/src/GeomAdaptor/GeomAdaptor_Curve.cxx @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -138,7 +137,8 @@ void GeomAdaptor_Curve::load(const Handle(Geom_Curve)& C, myLast = ULast; myCurveCache.Nullify(); - if ( myCurve != C) { + if (myCurve != C) + { myCurve = C; myNestedEvaluator.Nullify(); myBSplineCurve.Nullify(); @@ -524,36 +524,6 @@ Standard_Real GeomAdaptor_Curve::Period() const return myCurve->LastParameter() - myCurve->FirstParameter(); } -//======================================================================= -//function : RebuildCache -//purpose : -//======================================================================= -void GeomAdaptor_Curve::RebuildCache(const Standard_Real theParameter) const -{ - if (myTypeCurve == GeomAbs_BezierCurve) - { - // Create cache for Bezier - Handle(Geom_BezierCurve) aBezier = Handle(Geom_BezierCurve)::DownCast(myCurve); - Standard_Integer aDeg = aBezier->Degree(); - TColStd_Array1OfReal aFlatKnots(BSplCLib::FlatBezierKnots(aDeg), 1, 2 * (aDeg + 1)); - if (myCurveCache.IsNull()) - myCurveCache = new BSplCLib_Cache(aDeg, aBezier->IsPeriodic(), aFlatKnots, - aBezier->Poles(), aBezier->Weights()); - myCurveCache->BuildCache(theParameter, aDeg, aBezier->IsPeriodic(), aFlatKnots, - aBezier->Poles(), aBezier->Weights()); -} - else if (myTypeCurve == GeomAbs_BSplineCurve) -{ - // Create cache for B-spline - if (myCurveCache.IsNull()) - myCurveCache = new BSplCLib_Cache(myBSplineCurve->Degree(), myBSplineCurve->IsPeriodic(), - myBSplineCurve->KnotSequence(), myBSplineCurve->Poles(), myBSplineCurve->Weights()); - myCurveCache->BuildCache(theParameter, myBSplineCurve->Degree(), - myBSplineCurve->IsPeriodic(), myBSplineCurve->KnotSequence(), - myBSplineCurve->Poles(), myBSplineCurve->Weights()); -} -} - //======================================================================= //function : IsBoundary //purpose : @@ -585,6 +555,34 @@ Standard_Boolean GeomAdaptor_Curve::IsBoundary(const Standard_Real theU, return Standard_False; } +//======================================================================= +//function : CreateCache +//purpose : +//======================================================================= + +void GeomAdaptor_Curve::CreateCache() const +{ + switch (myTypeCurve) + { + case GeomAbs_BezierCurve: { + // Create cache for Bezier + Handle(Geom_BezierCurve) aBezier = Handle(Geom_BezierCurve)::DownCast(myCurve); + myCurveCache = new BSplCLib_MultiSpanCache3D(aBezier->Degree(), aBezier->IsPeriodic(), + aBezier->Poles(), aBezier->Weights()); + break; + } + case GeomAbs_BSplineCurve: + // Create cache for B-spline + myCurveCache = new BSplCLib_MultiSpanCache3D( + myBSplineCurve->Degree(), myBSplineCurve->IsPeriodic(), + &myBSplineCurve->Knots(), &myBSplineCurve->Multiplicities(), + &myBSplineCurve->KnotSequence(), myBSplineCurve->Poles(), myBSplineCurve->Weights()); + break; + default: // avoid gcc compilation warnings + break; + } +} + //======================================================================= //function : Value //purpose : @@ -611,14 +609,11 @@ void GeomAdaptor_Curve::D0(const Standard_Real U, gp_Pnt& P) const { Standard_Integer aStart = 0, aFinish = 0; if (IsBoundary(U, aStart, aFinish)) - { myBSplineCurve->LocalD0(U, aStart, aFinish, P); - } else { - // use cached data - if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U)) - RebuildCache(U); + if (myCurveCache.IsNull()) + CreateCache(); myCurveCache->D0(U, P); } break; @@ -647,14 +642,11 @@ void GeomAdaptor_Curve::D1(const Standard_Real U, gp_Pnt& P, gp_Vec& V) const { Standard_Integer aStart = 0, aFinish = 0; if (IsBoundary(U, aStart, aFinish)) - { myBSplineCurve->LocalD1(U, aStart, aFinish, P, V); - } else { - // use cached data - if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U)) - RebuildCache(U); + if (myCurveCache.IsNull()) + CreateCache(); myCurveCache->D1(U, P, V); } break; @@ -684,14 +676,11 @@ void GeomAdaptor_Curve::D2(const Standard_Real U, { Standard_Integer aStart = 0, aFinish = 0; if (IsBoundary(U, aStart, aFinish)) - { myBSplineCurve->LocalD2(U, aStart, aFinish, P, V1, V2); - } else { - // use cached data - if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U)) - RebuildCache(U); + if (myCurveCache.IsNull()) + CreateCache(); myCurveCache->D2(U, P, V1, V2); } break; @@ -722,14 +711,11 @@ void GeomAdaptor_Curve::D3(const Standard_Real U, { Standard_Integer aStart = 0, aFinish = 0; if (IsBoundary(U, aStart, aFinish)) - { myBSplineCurve->LocalD3(U, aStart, aFinish, P, V1, V2, V3); - } else { - // use cached data - if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U)) - RebuildCache(U); + if (myCurveCache.IsNull()) + CreateCache(); myCurveCache->D3(U, P, V1, V2, V3); } break; diff --git a/src/GeomAdaptor/GeomAdaptor_Curve.hxx b/src/GeomAdaptor/GeomAdaptor_Curve.hxx index 690480906c..c736720376 100644 --- a/src/GeomAdaptor/GeomAdaptor_Curve.hxx +++ b/src/GeomAdaptor/GeomAdaptor_Curve.hxx @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -228,9 +228,8 @@ private: //! Check theU relates to start or finish point of B-spline curve and return indices of span the point is located Standard_Boolean IsBoundary(const Standard_Real theU, Standard_Integer& theSpanStart, Standard_Integer& theSpanFinish) const; - //! Rebuilds B-spline cache - //! \param theParameter the value on the knot axis which identifies the caching span - void RebuildCache (const Standard_Real theParameter) const; + //! Allocates memory for a cache object + void CreateCache() const; Handle(Geom_Curve) myCurve; @@ -239,7 +238,7 @@ private: Standard_Real myLast; Handle(Geom_BSplineCurve) myBSplineCurve; ///< B-spline representation to prevent castings - mutable Handle(BSplCLib_Cache) myCurveCache; ///< Cached data for B-spline or Bezier curve + mutable Handle(BSplCLib_MultiSpanCache3D) myCurveCache; ///< Cached data for B-spline or Bezier curve Handle(GeomEvaluator_Curve) myNestedEvaluator; ///< Calculates value of offset curve diff --git a/src/GeomAdaptor/GeomAdaptor_Surface.cxx b/src/GeomAdaptor/GeomAdaptor_Surface.cxx index 24e054270b..ebb65b5312 100644 --- a/src/GeomAdaptor/GeomAdaptor_Surface.cxx +++ b/src/GeomAdaptor/GeomAdaptor_Surface.cxx @@ -134,7 +134,8 @@ void GeomAdaptor_Surface::load(const Handle(Geom_Surface)& S, myVLast = VLast; mySurfaceCache.Nullify(); - if ( mySurface != S) { + if (mySurface != S) + { mySurface = S; myNestedEvaluator.Nullify(); myBSplineSurface.Nullify(); @@ -179,10 +180,9 @@ void GeomAdaptor_Surface::load(const Handle(Geom_Surface)& S, new GeomEvaluator_SurfaceOfExtrusion (aBaseAdaptor, myExtSurf->Direction()); } else if (TheType == STANDARD_TYPE(Geom_BezierSurface)) - { mySurfaceType = GeomAbs_BezierSurface; - } - else if (TheType == STANDARD_TYPE(Geom_BSplineSurface)) { + else if (TheType == STANDARD_TYPE(Geom_BSplineSurface)) + { mySurfaceType = GeomAbs_BSplineSurface; myBSplineSurface = Handle(Geom_BSplineSurface)::DownCast(mySurface); } @@ -653,42 +653,34 @@ Standard_Real GeomAdaptor_Surface::VPeriod() const } //======================================================================= -//function : RebuildCache +//function : CreateCache //purpose : //======================================================================= -void GeomAdaptor_Surface::RebuildCache(const Standard_Real theU, - const Standard_Real theV) const + +void GeomAdaptor_Surface::CreateCache() const { - if (mySurfaceType == GeomAbs_BezierSurface) + switch (mySurfaceType) { + case GeomAbs_BezierSurface: { // Create cache for Bezier Handle(Geom_BezierSurface) aBezier = Handle(Geom_BezierSurface)::DownCast(mySurface); - Standard_Integer aDegU = aBezier->UDegree(); - Standard_Integer aDegV = aBezier->VDegree(); - TColStd_Array1OfReal aFlatKnotsU(BSplCLib::FlatBezierKnots(aDegU), 1, 2 * (aDegU + 1)); - TColStd_Array1OfReal aFlatKnotsV(BSplCLib::FlatBezierKnots(aDegV), 1, 2 * (aDegV + 1)); - if (mySurfaceCache.IsNull()) - mySurfaceCache = new BSplSLib_Cache( - aDegU, aBezier->IsUPeriodic(), aFlatKnotsU, - aDegV, aBezier->IsVPeriodic(), aFlatKnotsV, + mySurfaceCache = new BSplSLib_MultiSpanCache( + aBezier->UDegree(), aBezier->IsUPeriodic(), + aBezier->VDegree(), aBezier->IsVPeriodic(), aBezier->Poles(), aBezier->Weights()); - mySurfaceCache->BuildCache(theU, theV, - aDegU, aBezier->IsUPeriodic(), aFlatKnotsU, - aDegV, aBezier->IsVPeriodic(), aFlatKnotsV, - aBezier->Poles(), aBezier->Weights()); + break; } - else if (mySurfaceType == GeomAbs_BSplineSurface) - { + case GeomAbs_BSplineSurface: // Create cache for B-spline - if (mySurfaceCache.IsNull()) - mySurfaceCache = new BSplSLib_Cache( - myBSplineSurface->UDegree(), myBSplineSurface->IsUPeriodic(), myBSplineSurface->UKnotSequence(), - myBSplineSurface->VDegree(), myBSplineSurface->IsVPeriodic(), myBSplineSurface->VKnotSequence(), + mySurfaceCache = new BSplSLib_MultiSpanCache( + myBSplineSurface->UDegree(), myBSplineSurface->IsUPeriodic(), &myBSplineSurface->UKnots(), + &myBSplineSurface->UMultiplicities(), &myBSplineSurface->UKnotSequence(), + myBSplineSurface->VDegree(), myBSplineSurface->IsVPeriodic(), &myBSplineSurface->VKnots(), + &myBSplineSurface->VMultiplicities(), &myBSplineSurface->VKnotSequence(), myBSplineSurface->Poles(), myBSplineSurface->Weights()); - mySurfaceCache->BuildCache(theU, theV, - myBSplineSurface->UDegree(), myBSplineSurface->IsUPeriodic(), myBSplineSurface->UKnotSequence(), - myBSplineSurface->VDegree(), myBSplineSurface->IsVPeriodic(), myBSplineSurface->VKnotSequence(), - myBSplineSurface->Poles(), myBSplineSurface->Weights()); + break; + default: // avoid gcc compilation warnings + break; } } @@ -717,8 +709,8 @@ void GeomAdaptor_Surface::D0(const Standard_Real U, { case GeomAbs_BezierSurface: case GeomAbs_BSplineSurface: - if (mySurfaceCache.IsNull() || !mySurfaceCache->IsCacheValid(U, V)) - RebuildCache(U, V); + if (mySurfaceCache.IsNull()) + CreateCache(); mySurfaceCache->D0(U, V, P); break; @@ -747,25 +739,28 @@ void GeomAdaptor_Surface::D1(const Standard_Real U, gp_Vec& D1U, gp_Vec& D1V ) const { - Standard_Integer Ideb, Ifin, IVdeb, IVfin, USide=0, VSide=0; Standard_Real u = U, v = V; - if (Abs(U-myUFirst) <= myTolU) {USide= 1; u = myUFirst;} - else if (Abs(U-myULast) <= myTolU) {USide= -1; u = myULast;} - if (Abs(V-myVFirst) <= myTolV) {VSide= 1; v = myVFirst;} - else if (Abs(V-myVLast) <= myTolV) {VSide= -1; v = myVLast;} switch(mySurfaceType) { case GeomAbs_BezierSurface: case GeomAbs_BSplineSurface: { - if (!myBSplineSurface.IsNull() && - (USide != 0 || VSide != 0) && + Standard_Integer Ideb, Ifin, IVdeb, IVfin, USide = 0, VSide = 0; + if (!myBSplineSurface.IsNull()) + { + if (Abs(U - myUFirst) <= myTolU) { USide = 1; u = myUFirst; } + else if (Abs(U - myULast) <= myTolU) { USide = -1; u = myULast; } + if (Abs(V - myVFirst) <= myTolV) { VSide = 1; v = myVFirst; } + else if (Abs(V - myVLast) <= myTolV) { VSide = -1; v = myVLast; } + } + + if ((USide != 0 || VSide != 0) && IfUVBound(u, v, Ideb, Ifin, IVdeb, IVfin, USide, VSide)) myBSplineSurface->LocalD1(u, v, Ideb, Ifin, IVdeb, IVfin, P, D1U, D1V); else { - if (mySurfaceCache.IsNull() || !mySurfaceCache->IsCacheValid(U, V)) - RebuildCache(U, V); - mySurfaceCache->D1(U, V, P, D1U, D1V); + if (mySurfaceCache.IsNull()) + CreateCache(); + mySurfaceCache->D1(u, v, P, D1U, D1V); } break; } @@ -797,25 +792,28 @@ void GeomAdaptor_Surface::D2(const Standard_Real U, gp_Vec& D2V, gp_Vec& D2UV) const { - Standard_Integer Ideb, Ifin, IVdeb, IVfin, USide=0, VSide=0; Standard_Real u = U, v = V; - if (Abs(U-myUFirst) <= myTolU) {USide= 1; u = myUFirst;} - else if (Abs(U-myULast) <= myTolU) {USide= -1; u = myULast;} - if (Abs(V-myVFirst) <= myTolV) {VSide= 1; v = myVFirst;} - else if (Abs(V-myVLast) <= myTolV) {VSide= -1; v = myVLast;} switch(mySurfaceType) { case GeomAbs_BezierSurface: case GeomAbs_BSplineSurface: { - if (!myBSplineSurface.IsNull() && - (USide != 0 || VSide != 0) && + Standard_Integer Ideb, Ifin, IVdeb, IVfin, USide = 0, VSide = 0; + if (!myBSplineSurface.IsNull()) + { + if (Abs(U - myUFirst) <= myTolU) { USide = 1; u = myUFirst; } + else if (Abs(U - myULast) <= myTolU) { USide = -1; u = myULast; } + if (Abs(V - myVFirst) <= myTolV) { VSide = 1; v = myVFirst; } + else if (Abs(V - myVLast) <= myTolV) { VSide = -1; v = myVLast; } + } + + if ((USide != 0 || VSide != 0) && IfUVBound(u, v, Ideb, Ifin, IVdeb, IVfin, USide, VSide)) myBSplineSurface->LocalD2(u, v, Ideb, Ifin, IVdeb, IVfin, P, D1U, D1V, D2U, D2V, D2UV); else { - if (mySurfaceCache.IsNull() || !mySurfaceCache->IsCacheValid(U, V)) - RebuildCache(U, V); - mySurfaceCache->D2(U, V, P, D1U, D1V, D2U, D2V, D2UV); + if (mySurfaceCache.IsNull()) + CreateCache(); + mySurfaceCache->D2(u, v, P, D1U, D1V, D2U, D2V, D2UV); } break; } diff --git a/src/GeomAdaptor/GeomAdaptor_Surface.hxx b/src/GeomAdaptor/GeomAdaptor_Surface.hxx index 2f0d4838c3..303581e213 100644 --- a/src/GeomAdaptor/GeomAdaptor_Surface.hxx +++ b/src/GeomAdaptor/GeomAdaptor_Surface.hxx @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -256,11 +256,9 @@ private: Standard_EXPORT Standard_Boolean IfUVBound (const Standard_Real U, const Standard_Real V, Standard_Integer& Ideb, Standard_Integer& Ifin, Standard_Integer& IVdeb, Standard_Integer& IVfin, const Standard_Integer USide, const Standard_Integer VSide) const; Standard_EXPORT void load (const Handle(Geom_Surface)& S, const Standard_Real UFirst, const Standard_Real ULast, const Standard_Real VFirst, const Standard_Real VLast, const Standard_Real TolU = 0.0, const Standard_Real TolV = 0.0); - - //! Rebuilds B-spline cache - //! \param theU first parameter to identify the span for caching - //! \param theV second parameter to identify the span for caching - Standard_EXPORT void RebuildCache (const Standard_Real theU, const Standard_Real theV) const; + + //! Allocates memory for a cache object + void CreateCache() const; Handle(Geom_Surface) mySurface; @@ -272,7 +270,7 @@ private: Standard_Real myTolV; Handle(Geom_BSplineSurface) myBSplineSurface; ///< B-spline representation to prevent downcasts - mutable Handle(BSplSLib_Cache) mySurfaceCache; ///< Cached data for B-spline or Bezier surface + mutable Handle(BSplSLib_MultiSpanCache) mySurfaceCache; ///< Cached data for B-spline or Bezier surface protected: GeomAbs_SurfaceType mySurfaceType; diff --git a/src/QABugs/QABugs_19.cxx b/src/QABugs/QABugs_19.cxx index 36fff1fd04..95b8706a55 100644 --- a/src/QABugs/QABugs_19.cxx +++ b/src/QABugs/QABugs_19.cxx @@ -5106,6 +5106,66 @@ static Standard_Integer OCC27065(Draw_Interpretor& di, return 0; } +//======================================================================= +//function : OCC27074 +//purpose : Calculate value of B-spline surface using adaptor with multi-span cache +//======================================================================= +static Standard_Integer OCC27074(Draw_Interpretor& theDI, Standard_Integer theArgc, const char** theArgv) +{ + if (theArgc < 3 && theArgc > 4) + { + std::cout << "Incorrect number of arguments. See usage:" << std::endl; + theDI.PrintHelp(theArgv[0]); + return 1; + } + + Handle(Geom_Surface) aSurf = DrawTrSurf::GetSurface(theArgv[1]); + GeomAdaptor_Surface anAdaptor(aSurf); + + Standard_Integer aNbValues = Draw::Atoi(theArgv[2]); + Standard_Boolean isUseAdaptor = theArgc > 3 && theArgv[3][0] == '-' && theArgv[3][1] == 'a'; + + // Number of values to be calculated along each coordinate + Standard_Integer aNbU = (Standard_Integer)Sqrt(aNbValues); + Standard_Integer aNbV = (Standard_Integer)Ceiling((Standard_Real)aNbValues / aNbU); + + Standard_Real aU1, aU2, aV1, aV2; + aSurf->Bounds(aU1, aU2, aV1, aV2); + + Standard_Real aStepU = (aU2 - aU1) / (aNbU - 1); + Standard_Real aStepV = (aV2 - aV1) / (aNbV - 1); + + // Calculate values of surface to fill multi-span cache as much as possible. + // The parameters are divided to clusters by NxN points. Each time it is calculated + // one point from cluster and then the point from next cluster is calculated. + Standard_Integer aClusterSize = 100; + if (aSurf->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface)) + { + Handle(Geom_BSplineSurface) aBSpl = Handle(Geom_BSplineSurface)::DownCast(aSurf); + Standard_Integer aScaleU = aNbU / (aBSpl->NbUKnots() - 1); + Standard_Integer aScaleV = aNbV / (aBSpl->NbVKnots() - 1); + aClusterSize = Min(aScaleU, aScaleV); + } + + Standard_Real aCurU, aCurV; + for (Standard_Integer aClusterU = 0; aClusterU < aClusterSize; ++aClusterU) + for (Standard_Integer anIndU = aClusterU; anIndU < aNbU; anIndU += aClusterSize) + { + aCurU = aU1 + aStepU * anIndU; + for (Standard_Integer aClusterV = 0; aClusterV < aClusterSize; ++aClusterV) + for (Standard_Integer anIndV = aClusterV; anIndV < aNbV; anIndV += aClusterSize) + { + aCurV = aV1 + aStepV * anIndV; + if (isUseAdaptor) + anAdaptor.Value(aCurU, aCurV); + else + aSurf->Value(aCurU, aCurV); + } + } + + return 0; +} + //======================================================================== //function : OCC27318 //purpose : Creates a box that is not listed in map of AIS objects of ViewerTest @@ -5511,6 +5571,10 @@ void QABugs::Commands_19(Draw_Interpretor& theCommands) { "OCC27065 spine profile", __FILE__, OCC27065, group); + theCommands.Add ("OCC27074", + "OCC27074 surf N [-a]\nCalculate value of surface N times\n(-a means calculation using adaptor)", + __FILE__, OCC27074, group); + theCommands.Add ("OCC27318", "OCC27318: Creates a box that is not listed in map of AIS objects of ViewerTest", __FILE__, OCC27318, group); diff --git a/tests/blend/simple/Q6 b/tests/blend/simple/Q6 index 1c2a537fa4..01a4f96dbc 100644 --- a/tests/blend/simple/Q6 +++ b/tests/blend/simple/Q6 @@ -3,4 +3,4 @@ tscale s 0 0 0 SCALE explode s E blend result s SCALE*2 s_5 -checkprops result -s 1.65391e+008 +checkprops result -s 1.65391e+08 -eps 1.e-4 diff --git a/tests/bugs/modalg_6/bug25613_1 b/tests/bugs/modalg_6/bug25613_1 index 1f9b9cd322..3f307fe795 100644 --- a/tests/bugs/modalg_6/bug25613_1 +++ b/tests/bugs/modalg_6/bug25613_1 @@ -22,7 +22,7 @@ if { [ expr ($dist - $dist_good) ] < -$Tol } { puts "Error in xdistef command (cannot find maximal distance)" } -if { $dist > $dist_good } { +if { $dist > $dist_good + $Tol } { #Check if distance found is correct mkcurve c3d e diff --git a/tests/bugs/modalg_6/bug25613_2 b/tests/bugs/modalg_6/bug25613_2 index 10dcdf3e47..f0b3ee0d47 100644 --- a/tests/bugs/modalg_6/bug25613_2 +++ b/tests/bugs/modalg_6/bug25613_2 @@ -22,7 +22,7 @@ if { [ expr ($dist - $dist_good) ] < -$Tol } { puts "Error in xdistef command (cannot find maximal distance)" } -if { $dist > $dist_good } { +if { $dist > $dist_good + $Tol } { #Check if distance found is correct mkcurve c3d e diff --git a/tests/de/step_2/R2 b/tests/de/step_2/R2 index cc18f1564c..dbf4b23312 100644 --- a/tests/de/step_2/R2 +++ b/tests/de/step_2/R2 @@ -7,8 +7,8 @@ set ref_data { DATA : Faulties = 0 ( 0 ) Warnings = 0 ( 0 ) Summary = 0 ( 0 ) TPSTAT : Faulties = 0 ( 0 ) Warnings = 31 ( 28 ) Summary = 31 ( 28 ) CHECKSHAPE : Wires = 0 ( 0 ) Faces = 0 ( 0 ) Shells = 0 ( 0 ) Solids = 0 ( 0 ) -NBSHAPES : Solid = 0 ( 0 ) Shell = 1 ( 1 ) Face = 357 ( 357 ) Summary = 2004 ( 2003 ) -STATSHAPE : Solid = 0 ( 0 ) Shell = 1 ( 1 ) Face = 357 ( 357 ) FreeWire = 0 ( 0 ) FreeEdge = 0 ( 0 ) SharedEdge = 840 ( 839 ) +NBSHAPES : Solid = 0 ( 0 ) Shell = 1 ( 1 ) Face = 357 ( 357 ) Summary = 2005 ( 2003 ) +STATSHAPE : Solid = 0 ( 0 ) Shell = 1 ( 1 ) Face = 357 ( 357 ) FreeWire = 0 ( 0 ) FreeEdge = 0 ( 0 ) SharedEdge = 841 ( 839 ) TOLERANCE : MaxTol = 0.007356791914 ( 0.009485808595 ) AvgTol = 0.0003528568313 ( 0.001207996284 ) LABELS : N0Labels = 1 ( 1 ) N1Labels = 0 ( 0 ) N2Labels = 0 ( 0 ) TotalLabels = 1 ( 1 ) NameLabels = 1 ( 1 ) ColorLabels = 1 ( 1 ) LayerLabels = 0 ( 0 ) PROPS : Centroid = 0 ( 0 ) Volume = 0 ( 0 ) Area = 0 ( 0 ) diff --git a/tests/de/step_2/T1 b/tests/de/step_2/T1 index 7cab7c8f0e..3b32cdc71c 100644 --- a/tests/de/step_2/T1 +++ b/tests/de/step_2/T1 @@ -7,8 +7,8 @@ set ref_data { DATA : Faulties = 0 ( 0 ) Warnings = 0 ( 0 ) Summary = 0 ( 0 ) TPSTAT : Faulties = 0 ( 0 ) Warnings = 31 ( 28 ) Summary = 31 ( 28 ) CHECKSHAPE : Wires = 0 ( 0 ) Faces = 0 ( 0 ) Shells = 0 ( 0 ) Solids = 0 ( 0 ) -NBSHAPES : Solid = 1 ( 1 ) Shell = 1 ( 1 ) Face = 357 ( 357 ) Summary = 2005 ( 2004 ) -STATSHAPE : Solid = 1 ( 1 ) Shell = 1 ( 1 ) Face = 357 ( 357 ) FreeWire = 0 ( 0 ) FreeEdge = 0 ( 0 ) SharedEdge = 840 ( 839 ) +NBSHAPES : Solid = 1 ( 1 ) Shell = 1 ( 1 ) Face = 357 ( 357 ) Summary = 2006 ( 2004 ) +STATSHAPE : Solid = 1 ( 1 ) Shell = 1 ( 1 ) Face = 357 ( 357 ) FreeWire = 0 ( 0 ) FreeEdge = 0 ( 0 ) SharedEdge = 841 ( 839 ) TOLERANCE : MaxTol = 0.007356791914 ( 0.009485808595 ) AvgTol = 0.0003528126958 ( 0.001207999522 ) LABELS : N0Labels = 1 ( 1 ) N1Labels = 0 ( 0 ) N2Labels = 0 ( 0 ) TotalLabels = 1 ( 1 ) NameLabels = 1 ( 1 ) ColorLabels = 0 ( 0 ) LayerLabels = 0 ( 0 ) PROPS : Centroid = 0 ( 0 ) Volume = 0 ( 0 ) Area = 0 ( 0 ) diff --git a/tests/perf/bspline/hugenurbs b/tests/perf/bspline/hugenurbs new file mode 100644 index 0000000000..9d76b4f339 --- /dev/null +++ b/tests/perf/bspline/hugenurbs @@ -0,0 +1,39 @@ +puts "========" +puts "CR27074" +puts "========" +puts "" +####################################################################### +# Compare allocated memory for evaluation of huge NURBS surface +####################################################################### + +pload QAcommands + +cpulimit 1000 + +# create simple B-spline +bsplinesurf s \ +1 2 0 2 1 2 \ +1 2 0 2 1 2 \ +0 0 0 1 1 0 1 1 \ +0 1 0 1 1 1 1 1 + +# increase number of spans +set nbspans 1000 +for {set i 1} {$i < $nbspans} {incr i} { + set knot [expr double($i) / $nbspans] + insertuknot s $knot 1 + insertvknot s $knot 1 +} + +# increase degree +set deg 5 +incudeg s $deg +incvdeg s $deg + +# calculate values of B-spline +set nbiter 1000000 +dchrono t reset +dchrono t start +OCC27074 s $nbiter -a +dchrono t stop +dchrono t show diff --git a/tests/perf/bspline/multispan b/tests/perf/bspline/multispan new file mode 100644 index 0000000000..f5f7ca1ad0 --- /dev/null +++ b/tests/perf/bspline/multispan @@ -0,0 +1,64 @@ +puts "========" +puts "CR27074" +puts "========" +puts "" +####################################################################### +# Compare performance of calculation value of NURBS surface with multi-span cache +####################################################################### + +pload QAcommands + +cpulimit 1000 + +bsplinesurf nsurf \ +5 5 0 6 1 1 4 1 5 1 8 6 \ +5 5 0 6 2 1 3 1 6 1 7 6 \ +0 0 0 1 2 0 0 1 5 0 -1 1 10 0 5 1 12 0 1 1 15 0 -3 1 16 0 -3 1 19 0 -4 1 24 0 0 1 \ +0 10 2 1 3 10 0 1 8 10 5 1 10 10 3 1 12 10 2 1 15 10 0 1 20 10 5 1 21 10 3 1 24 10 0 1 \ +0 20 10 1 4 20 4 1 7 20 4 1 10 20 20 1 12 20 10 1 16 20 4 1 19 20 4 1 20 20 10 1 24 20 0 1 \ +0 30 0 1 2 30 0 1 8 30 0 1 10 30 0 1 12 30 0 1 14 30 0 1 20 30 0 1 22 30 0 1 24 30 0 1 \ +0 40 -1 1 4 40 5 1 9 40 1 1 10 40 5 1 12 40 -1 1 16 40 5 1 21 40 1 1 22 40 5 1 24 40 0 1 \ +0 50 5 1 4 50 10 1 6 50 10 1 10 50 5 1 12 50 5 1 16 50 10 1 18 50 10 1 20 50 5 1 24 50 0 1 \ +0 60 4 1 3 60 -3 1 7 60 -4 1 10 60 4 1 12 60 4 1 15 60 -3 1 19 60 -4 1 20 60 4 1 24 60 0 1 \ +0 70 -5 1 3 70 0 1 5 70 0 1 10 70 -3 1 12 70 -5 1 15 70 0 1 17 70 0 1 20 70 -3 1 24 70 0 1 \ +0 80 7 1 3 80 1 1 7 80 3 1 10 80 0 1 12 80 7 1 15 80 1 1 19 80 3 1 21 80 0 1 24 80 0 1 + +bsplinesurf rsurf \ +5 5 0 6 1 1 4 1 5 1 8 6 \ +5 5 0 6 2 1 3 1 6 1 7 6 \ +0 0 0 1 2 0 0 1 5 0 -1 1 10 0 5 2 12 0 1 1 15 0 -3 2 16 0 -3 1 19 0 -4 1 24 0 0 1 \ +0 10 2 3 3 10 0 1 8 10 5 3 10 10 3 1 12 10 2 3 15 10 0 1 20 10 5 3 21 10 3 1 24 10 0 2 \ +0 20 10 1 4 20 4 3 7 20 4 2 10 20 20 4 12 20 10 1 16 20 4 3 19 20 4 2 20 20 10 4 24 20 0 1 \ +0 30 0 2 2 30 0 1 8 30 0 1 10 30 0 2 12 30 0 2 14 30 0 1 20 30 0 1 22 30 0 2 24 30 0 3 \ +0 40 -1 1 4 40 5 2 9 40 1 3 10 40 5 2 12 40 -1 1 16 40 5 2 21 40 1 3 22 40 5 2 24 40 0 1 \ +0 50 5 1 4 50 10 5 6 50 10 5 10 50 5 1 12 50 5 1 16 50 10 5 18 50 10 5 20 50 5 1 24 50 0 2 \ +0 60 4 3 3 60 -3 1 7 60 -4 1 10 60 4 1 12 60 4 3 15 60 -3 1 19 60 -4 1 20 60 4 1 24 60 0 1 \ +0 70 -5 5 3 70 0 1 5 70 0 1 10 70 -3 2 12 70 -5 5 15 70 0 1 17 70 0 1 20 70 -3 2 24 70 0 3 \ +0 80 7 1 3 80 1 2 7 80 3 1 10 80 0 1 12 80 7 1 15 80 1 2 19 80 3 1 21 80 0 1 24 80 0 1 + + +set surfaces [list nsurf rsurf] +# number of values to be calculated +set nbiter 4000000 + +foreach s $surfaces { + # calculate values without adaptor + dchrono t reset + dchrono t start + OCC27074 $s $nbiter + dchrono t stop + set elapsed [dchrono t show] + regexp {CPU user time: ([-0-9.+eE]+) seconds} ${elapsed} full cpu_noadaptor + + # calculate values using adaptor + dchrono t reset + dchrono t start + OCC27074 $s $nbiter -a + dchrono t stop + set elapsed [dchrono t show] + regexp {CPU user time: ([-0-9.+eE]+) seconds} ${elapsed} full cpu_adaptor + + if {$cpu_adaptor >= $cpu_noadaptor} { + puts "ERROR: Multi-span cached adaptor is slower than surface" + } +}