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
* 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.
+
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;
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;
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;
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;
}
-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
}
-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
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
}
-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;
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;
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;
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;
}
-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;
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;
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
//! \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
// 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)
--- /dev/null
+// 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 <BSplCLib.hxx>
+#include <ElCLib.hxx>
+
+template<class POINT_TYPE, class VEC_TYPE>
+BSplCLib_MultiSpanCacheBase<POINT_TYPE, VEC_TYPE>::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<class POINT_TYPE, class VEC_TYPE>
+BSplCLib_MultiSpanCacheBase<POINT_TYPE, VEC_TYPE>::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<class POINT_TYPE, class VEC_TYPE>
+BSplCLib_MultiSpanCacheBase<POINT_TYPE, VEC_TYPE>::~BSplCLib_MultiSpanCacheBase()
+{
+ Standard_Integer aSize = (Standard_Integer)myCaches.Size();
+ for (Standard_Integer i = 0; i < aSize; ++i)
+ myCaches[i].Nullify();
+}
+
+template<class POINT_TYPE, class VEC_TYPE>
+void BSplCLib_MultiSpanCacheBase<POINT_TYPE, VEC_TYPE>::D0(const Standard_Real theParameter,
+ POINT_TYPE& thePoint)
+{
+ Standard_Real aPar = theParameter;
+ const Handle(BSplCLib_Cache)& aCache = FindCache(aPar);
+ aCache->D0(aPar, thePoint);
+}
+
+template<class POINT_TYPE, class VEC_TYPE>
+void BSplCLib_MultiSpanCacheBase<POINT_TYPE, VEC_TYPE>::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<class POINT_TYPE, class VEC_TYPE>
+void BSplCLib_MultiSpanCacheBase<POINT_TYPE, VEC_TYPE>::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<class POINT_TYPE, class VEC_TYPE>
+void BSplCLib_MultiSpanCacheBase<POINT_TYPE, VEC_TYPE>::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<class POINT_TYPE, class VEC_TYPE>
+Standard_Integer BSplCLib_MultiSpanCacheBase<POINT_TYPE, VEC_TYPE>::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<class POINT_TYPE, class VEC_TYPE>
+const Handle(BSplCLib_Cache)&
+BSplCLib_MultiSpanCacheBase<POINT_TYPE, VEC_TYPE>::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;
+}
--- /dev/null
+// 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 <BSplCLib_Cache.hxx>
+#include <NCollection_LocalArray.hxx>
+#include <TColStd_Array1OfInteger.hxx>
+
+//! \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 POINT_TYPE, class VEC_TYPE>
+class BSplCLib_MultiSpanCacheBase
+{
+ typedef NCollection_Array1<POINT_TYPE> 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<Handle(BSplCLib_Cache), 1> 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<gp_Pnt2d, gp_Vec2d>, 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<gp_Pnt2d, gp_Vec2d>(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<gp_Pnt2d, gp_Vec2d>(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<gp_Pnt, gp_Vec>, 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<gp_Pnt, gp_Vec>(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<gp_Pnt, gp_Vec>(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 <BSplCLib_MultiSpanCache.gxx>
+
+#endif
BSplCLib_EvaluatorFunction.hxx
BSplCLib_KnotDistribution.hxx
BSplCLib_MultDistribution.hxx
+BSplCLib_MultiSpanCache.gxx
+BSplCLib_MultiSpanCache.hxx
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);
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;
}
-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];
}
-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();
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]);
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();
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]);
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]);
}
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
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
//! \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
//! \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:
// 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)
--- /dev/null
+// 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 <BSplSLib_MultiSpanCache.hxx>
+
+#include <BSplCLib.hxx>
+#include <ElCLib.hxx>
+#include <Precision.hxx>
+
+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;
+}
--- /dev/null
+// 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 <BSplSLib_Cache.hxx>
+#include <NCollection_LocalArray.hxx>
+
+//! \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<Handle(BSplSLib_Cache), 1> 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
BSplSLib_Cache.cxx
BSplSLib_Cache.hxx
BSplSLib_EvaluatorFunction.hxx
+BSplSLib_MultiSpanCache.cxx
+BSplSLib_MultiSpanCache.hxx
#include <Adaptor2d_HCurve2d.hxx>
#include <BSplCLib.hxx>
-#include <BSplCLib_Cache.hxx>
#include <Geom2d_BezierCurve.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <Geom2d_Circle.hxx>
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);
}
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 :
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 :
{
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;
{
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;
{
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;
{
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;
#include <GeomAbs_CurveType.hxx>
#include <Standard_Real.hxx>
-#include <BSplCLib_Cache.hxx>
+#include <BSplCLib_MultiSpanCache.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <GeomAbs_Shape.hxx>
#include <Standard_Integer.hxx>
//! 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;
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
#include <Adaptor3d_HCurve.hxx>
#include <BSplCLib.hxx>
-#include <BSplCLib_Cache.hxx>
#include <Geom_BezierCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_Circle.hxx>
myLast = ULast;
myCurveCache.Nullify();
- if ( myCurve != C) {
+ if (myCurve != C)
+ {
myCurve = C;
myNestedEvaluator.Nullify();
myBSplineCurve.Nullify();
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 :
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 :
{
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;
{
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;
{
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;
{
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;
#include <GeomAbs_CurveType.hxx>
#include <Standard_Real.hxx>
-#include <BSplCLib_Cache.hxx>
+#include <BSplCLib_MultiSpanCache.hxx>
#include <Adaptor3d_Curve.hxx>
#include <GeomAbs_Shape.hxx>
#include <Standard_Integer.hxx>
//! 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;
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
myVLast = VLast;
mySurfaceCache.Nullify();
- if ( mySurface != S) {
+ if (mySurface != S)
+ {
mySurface = S;
myNestedEvaluator.Nullify();
myBSplineSurface.Nullify();
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);
}
}
//=======================================================================
-//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;
}
}
{
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;
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;
}
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;
}
#include <GeomAbs_SurfaceType.hxx>
#include <Standard_Real.hxx>
-#include <BSplSLib_Cache.hxx>
+#include <BSplSLib_MultiSpanCache.hxx>
#include <Adaptor3d_Surface.hxx>
#include <GeomAbs_Shape.hxx>
#include <Standard_Integer.hxx>
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;
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;
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
"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);
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
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
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
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 )
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 )
--- /dev/null
+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
--- /dev/null
+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"
+ }
+}