698 lines
22 KiB
C++
698 lines
22 KiB
C++
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CryEngine Source code
|
|
//
|
|
// File:BSplineOpen
|
|
// Declaration of
|
|
// interface IBSpline3Packed
|
|
// template <> struct TBSplineVec3dPackedBase
|
|
// template <> struct TBSplineVec3dPackedDesc
|
|
// template <> struct TBSplineVec3dPacked
|
|
//
|
|
// History:
|
|
// 06/21/2002 :Created by Sergiy Migdalskiy <sergiy@crytek.de>
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
#pragma once
|
|
|
|
#include "BSplineOpen.h"
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Packed (minimal memory footprint) representation of BSpline.
|
|
// Keeps the data in 1- or 2-byte fixed-point scaled numbers
|
|
// CAUTION: Avoid copying it too much, the data gets copied upon
|
|
// each invokation of the copy constructor.
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// interface to all representations of the packed spline
|
|
class IBSpline3Packed:
|
|
public _reference_target<unsigned short> // we don't need the alignment of 4 bytes here
|
|
{
|
|
public:
|
|
// apply the given scale to the spline (multiply the spline by scale
|
|
virtual void scale (float fScale) = 0;
|
|
|
|
// returns the size of the buffer required to pack in the spline in the current state
|
|
virtual int getPackedSize()const = 0; // used
|
|
|
|
// returns the size of the array that follows the descriptor structure
|
|
virtual int getRawDataSize()const = 0;
|
|
|
|
// returns the min corner of the bounding box for CPs
|
|
virtual Vec3 getCPMin ()const = 0;
|
|
// returns the max corner of the bounding box for CPs
|
|
virtual Vec3 getCPMax ()const = 0;
|
|
|
|
// returns the min time
|
|
virtual float getTimeMin() const = 0;
|
|
// returns the max time
|
|
virtual float getTimeMax () const = 0;
|
|
// returns the timespan range
|
|
virtual float getTimeRange() const = 0;
|
|
|
|
virtual int numKnots()const = 0;
|
|
virtual int numCPs()const = 0;
|
|
|
|
// unpacks this object out of the given storage;
|
|
// returns the size of storage used for unpacking; 0 means unpack failed
|
|
virtual int unpack(void* pBuffer, int nSize) = 0; // used
|
|
|
|
// clears the contents of the spline
|
|
virtual void clear() = 0;
|
|
|
|
// constructs a packed version of the given unpacked bspline
|
|
virtual void copy (BSplineVec3d* pSpline) = 0; // used
|
|
|
|
// packs the spline into the given buffer
|
|
virtual void pack (void* pBuffer) = 0; // used
|
|
|
|
// calculates the value of the spline at the specified point
|
|
virtual Vec3 getValue (float t) = 0;
|
|
|
|
// returns the CP from the array of value triplets
|
|
virtual Vec3 getCP (int nCP) = 0;
|
|
|
|
// returns the time
|
|
virtual float getKnotTime (int nKnot)const = 0;
|
|
|
|
virtual unsigned sizeofThis()const = 0;
|
|
};
|
|
|
|
TYPEDEF_AUTOPTR(IBSpline3Packed);
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
template <bool isOpen, typename FixedPointType>
|
|
struct TBSplineVec3dPackedBase
|
|
{
|
|
public:
|
|
// fixed-point values.
|
|
// may be unsigned short or unsigned char ONLY
|
|
typedef FixedPointType fixed;
|
|
|
|
enum
|
|
{
|
|
// total number of fixed values - may be overflow in the case of fixed == int
|
|
//numFixedValues = 1<<(sizeof(fixed)*8)),
|
|
// maximum fixed value representible
|
|
nMaxFixedValue = ((fixed)~0)
|
|
};
|
|
protected:
|
|
TBSplineVec3dPackedBase():
|
|
m_nDegree(1),
|
|
m_numKnots(0)
|
|
{
|
|
}
|
|
|
|
// degree of the spline
|
|
short m_nDegree;
|
|
// number of knots
|
|
short m_numKnots;
|
|
|
|
// the scale of the time values
|
|
struct Scale
|
|
{
|
|
// the default scale is make all fixed values represent the interval [0,1)
|
|
Scale():
|
|
fBase(0),
|
|
fScale(1.0f / (float)nMaxFixedValue)
|
|
{
|
|
}
|
|
|
|
float fBase;
|
|
float fScale;
|
|
|
|
inline float unpack (fixed fVal)const
|
|
{
|
|
return fBase + fScale * fVal;
|
|
}
|
|
|
|
fixed pack (float fVal)const
|
|
{
|
|
float f=fScale;
|
|
int i=nMaxFixedValue;
|
|
|
|
if (fVal <= fBase)
|
|
return 0;
|
|
if (fVal >= fBase + f*i)
|
|
return nMaxFixedValue;
|
|
|
|
return (fixed)((fVal-fBase) / fScale + 0.5);
|
|
}
|
|
|
|
// unpacks the values, assuming that there are 2 more Scale structures after this
|
|
Vec3 unpack (fixed*pVec)
|
|
{
|
|
return Vec3 (this[0].unpack(pVec[0]), this[1].unpack(pVec[1]), this[2].unpack(pVec[2]));
|
|
}
|
|
|
|
// initialize the structure base and scale so that the resulting fixed value range
|
|
// maps effectively the [min,max] closed interval
|
|
void initFromMinMax (float fMin, float fMax)
|
|
{
|
|
fBase = fMin;
|
|
fScale = (fMax-fMin) / nMaxFixedValue;
|
|
}
|
|
|
|
// returns the min representable value
|
|
float getMin () const
|
|
{
|
|
return fBase;
|
|
}
|
|
|
|
// rehtrns the max reprsentable value
|
|
float getMax () const
|
|
{
|
|
return fBase + getRange();
|
|
}
|
|
|
|
float getRange() const
|
|
{
|
|
float f=fScale;
|
|
int i=nMaxFixedValue;
|
|
return f * i;
|
|
}
|
|
|
|
void scale (float _scale)
|
|
{
|
|
fBase *= _scale;
|
|
fScale *= _scale;
|
|
}
|
|
};
|
|
// scale for each
|
|
Scale m_TimeScale;
|
|
Scale m_PosScale[3];
|
|
|
|
public:
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// This is the descriptor of class TBSplineVec3dPacked.
|
|
// it's used to plainly pack/unpack the spline and reuse this structure
|
|
template <bool isOpen = true, typename FixedPointType = unsigned char>
|
|
struct TBSplineVec3dPackedDesc:
|
|
public IBSpline3Packed,
|
|
public TBSplineVec3dPackedBase<isOpen,FixedPointType>
|
|
{
|
|
typedef TBSplineVec3dPackedBase<isOpen, FixedPointType> Base;
|
|
|
|
// apply the given scale to the spline (multiply the spline by scale
|
|
void scale (float fScale);
|
|
|
|
// returns the size of the buffer required to pack in the spline in the current state
|
|
int getPackedSize()const
|
|
{
|
|
return sizeof (Base) + this->getRawDataSize();
|
|
}
|
|
|
|
unsigned sizeofThis()const
|
|
{
|
|
return getPackedSize();
|
|
}
|
|
|
|
int numKnots()const
|
|
{
|
|
assert ((this->m_numKnots >= 2 && this->m_numKnots < 10000) || (this->m_numKnots==0 && this->m_nDegree==1));// boundary check
|
|
return this->m_numKnots;
|
|
}
|
|
int numCPs()const
|
|
{
|
|
assert (this->m_nDegree >= 1 && this->m_nDegree < 5);// boundary check
|
|
return this->m_numKnots + (isOpen? this->m_nDegree - 1 : -1);
|
|
}
|
|
// returns the number of raw data elements
|
|
int numRawDataElements()const
|
|
{
|
|
return (numKnots() - 2 + 3*numCPs());
|
|
}
|
|
// returns the size of the array that follows the descriptor structure
|
|
int getRawDataSize()const
|
|
{
|
|
return numRawDataElements()*sizeof(typename TBSplineVec3dPackedBase<isOpen,FixedPointType>::fixed);
|
|
}
|
|
|
|
// returns the min corner of the bounding box for CPs
|
|
Vec3 getCPMin ()const;
|
|
// returns the max corner of the bounding box for CPs
|
|
Vec3 getCPMax ()const;
|
|
|
|
// returns the min time
|
|
float getTimeMin() const;
|
|
// returns the max time
|
|
float getTimeMax () const;
|
|
// returns the timespan range
|
|
float getTimeRange() const;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// The spline packed implementation
|
|
template <bool isOpen = true, typename FixedPointType = unsigned char>
|
|
class TBSplineVec3dPacked:
|
|
public TBSplineVec3dPackedDesc<isOpen, FixedPointType>
|
|
{
|
|
public:
|
|
typedef TBSplineVec3dPackedDesc<isOpen, FixedPointType> Desc;
|
|
|
|
// constructs an empty spline (no knots, no keys)
|
|
// you can unpack or copy the
|
|
TBSplineVec3dPacked ();
|
|
|
|
// destructs
|
|
~TBSplineVec3dPacked (void);
|
|
|
|
// copies the packed version of the BSpline
|
|
TBSplineVec3dPacked (const TBSplineVec3dPacked<isOpen, FixedPointType>& that);
|
|
|
|
// unpacks this object out of the given storage;
|
|
// returns the size of storage used for unpacking; 0 means unpack failed
|
|
int unpack(void* pBuffer, int nSize);
|
|
|
|
// clears the contents of the spline
|
|
void clear();
|
|
|
|
// constructs a packed version of the given unpacked bspline
|
|
void copy (BSplineVec3d* pSpline);
|
|
|
|
// packs the spline into the given buffer
|
|
void pack (void* pBuffer);
|
|
|
|
// calculates the value of the spline at the specified point
|
|
Vec3 getValue (float t);
|
|
|
|
// returns the CP from the array of value triplets
|
|
Vec3 getCP (int nCP);
|
|
|
|
// returns the time
|
|
float getKnotTime (int nKnot)const;
|
|
|
|
// searches and returns the interval to which the given time belongs.
|
|
// each pair of knots defines interval [k1,k2)
|
|
// -1 is before the 0-th knot, numKnots()-1 is after the last knot
|
|
int findInterval (float fTime)const;
|
|
|
|
// returns the i-th basis function of degree d, given the time t
|
|
float getBasis (int i, int d, float t) const;
|
|
|
|
// returns the i-th basis function of degree d, given the time t and a hint, in which interval to search for it
|
|
float getBasis (int i, int d, float t, int nIntervalT) const;
|
|
protected:
|
|
// returns the value of the basis function of degree d, given the time t
|
|
// the knots of the basis function start at pKnotBegin, and the first knot before t is pKnotBeforeT
|
|
float getBasisUnsafe (int nKnotBegin, int d, float t, int nKnotBeforeT) const;
|
|
|
|
// plain array of fixed-point values scaled between the min and max time and position
|
|
// there are m_numKnots knot time values, immediately followed by m_numKnots+m_nDegree-1
|
|
// control point values, each control point value is 3 fixed values
|
|
FixedPointType* m_pData;
|
|
};
|
|
|
|
template <bool isOpen, typename FixedPointType>
|
|
TBSplineVec3dPacked<isOpen, FixedPointType>::TBSplineVec3dPacked(void):
|
|
m_pData(NULL)
|
|
{
|
|
}
|
|
|
|
template <bool isOpen, typename FixedPointType>
|
|
TBSplineVec3dPacked<isOpen, FixedPointType>::~TBSplineVec3dPacked(void)
|
|
{
|
|
clear();
|
|
}
|
|
|
|
|
|
// copies the packed version of the BSpline
|
|
template <bool isOpen, typename FixedPointType>
|
|
TBSplineVec3dPacked<isOpen, FixedPointType>::TBSplineVec3dPacked (const TBSplineVec3dPacked<isOpen,FixedPointType>& that):
|
|
Desc(that)
|
|
{
|
|
if (that.numKnots()) // if not an empty one
|
|
{
|
|
m_pData = new typename TBSplineVec3dPackedBase<isOpen,FixedPointType>::fixed[that.numRawDataElements()];
|
|
memcpy (m_pData, that.m_pData, that.getRawDataSize());
|
|
}
|
|
else
|
|
m_pData = NULL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// unpacks this object out of the given storage;
|
|
// returns the size of storage used for unpacking; 0 means unpack failed
|
|
template <bool isOpen, typename FixedPointType>
|
|
int TBSplineVec3dPacked<isOpen, FixedPointType>::unpack(void* pBuffer, int nSize)
|
|
{
|
|
clear();
|
|
|
|
if (nSize < sizeof(typename TBSplineVec3dPackedDesc<isOpen, FixedPointType>::Base))
|
|
return 0; // failed
|
|
|
|
memcpy (static_cast<typename TBSplineVec3dPackedDesc<isOpen, FixedPointType>::Base*>(this), pBuffer, sizeof(typename TBSplineVec3dPackedDesc<isOpen, FixedPointType>::Base));
|
|
|
|
if (nSize < (int)sizeof(typename TBSplineVec3dPackedDesc<isOpen, FixedPointType>::Base) + this->getRawDataSize())
|
|
{
|
|
clear();
|
|
return 0;
|
|
}
|
|
|
|
m_pData = (new typename TBSplineVec3dPackedBase<isOpen,FixedPointType>::fixed[this->numRawDataElements()]);
|
|
memcpy (m_pData, ((const typename TBSplineVec3dPackedDesc<isOpen, FixedPointType>::Base*)pBuffer)+1, this->getRawDataSize());
|
|
return sizeof(typename TBSplineVec3dPackedDesc<isOpen, FixedPointType>::Base) + this->getRawDataSize();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// clears the contents of the spline
|
|
template <bool isOpen, typename FixedPointType>
|
|
void TBSplineVec3dPacked<isOpen, FixedPointType>::clear()
|
|
{
|
|
if (m_pData)
|
|
{
|
|
delete[]m_pData;
|
|
m_pData = NULL;
|
|
}
|
|
|
|
this->m_nDegree = 1;
|
|
this->m_numKnots = 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// constructs a packed version of the given unpacked bspline
|
|
template <bool isOpen, typename FixedPointType>
|
|
void TBSplineVec3dPacked<isOpen, FixedPointType>::copy (BSplineVec3d* pSpline)
|
|
{
|
|
int i, nCoord;
|
|
assert (isOpen == pSpline->isOpen());
|
|
|
|
clear();
|
|
this->m_nDegree = pSpline->getDegree();
|
|
this->m_numKnots = pSpline->numKnots();
|
|
|
|
assert (this->numCPs() == pSpline->numCPs());
|
|
|
|
// find the time scale
|
|
this->m_TimeScale.initFromMinMax (pSpline->getKnotTime(0), pSpline->getKnotTime(this->m_numKnots-1));
|
|
|
|
// find the spacial scale for the CPs - min/max CP coordinates
|
|
Vec3 vMinCP, vMaxCP;
|
|
vMinCP = vMaxCP = pSpline->getCP(0);
|
|
|
|
for (i = 1; i < pSpline->numCPs(); ++i)
|
|
{
|
|
const Vec3& vCP = pSpline->getCP(i);
|
|
for (nCoord = 0; nCoord < 3; ++nCoord)
|
|
{
|
|
if (vMinCP[nCoord] > vCP[nCoord])
|
|
vMinCP[nCoord] = vCP[nCoord];
|
|
else
|
|
if (vMaxCP[nCoord] < vCP[nCoord])
|
|
vMaxCP[nCoord] = vCP[nCoord];
|
|
}
|
|
}
|
|
|
|
// map the min/max coordinates to the scales
|
|
for (nCoord = 0; nCoord < 3; ++nCoord)
|
|
{
|
|
this->m_PosScale[nCoord].initFromMinMax(vMinCP[nCoord], vMaxCP[nCoord]);
|
|
}
|
|
|
|
m_pData = new typename TBSplineVec3dPackedBase<isOpen,FixedPointType>::fixed[this->numRawDataElements()];
|
|
|
|
// copy the data (knots and CPs)
|
|
// We ignore the first and last knot, because information about them is already present in the scale structure
|
|
for (i = 0; i < pSpline->numKnots()-2; ++i)
|
|
m_pData[i] = this->m_TimeScale.pack(pSpline->getKnotTime(i+1));
|
|
|
|
// each CP has 3 coordinates, each mapped with different pos scale
|
|
for (i = 0; i < pSpline->numCPs(); ++i)
|
|
for (nCoord = 0; nCoord < 3; ++nCoord)
|
|
m_pData[i*3+nCoord+this->numKnots()-2] = this->m_PosScale[nCoord].pack (pSpline->getCP(i)[nCoord]);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// packs the spline into the given buffer
|
|
template <bool isOpen, typename FixedPointType>
|
|
void TBSplineVec3dPacked<isOpen, FixedPointType>::pack (void* pBuffer)
|
|
{
|
|
memcpy (pBuffer, static_cast<const typename TBSplineVec3dPackedDesc<isOpen, FixedPointType>::Base*>(this), sizeof(typename TBSplineVec3dPackedDesc<isOpen, FixedPointType>::Base));
|
|
memcpy (static_cast<typename TBSplineVec3dPackedDesc<isOpen, FixedPointType>::Base*>(pBuffer) + 1, m_pData, this->getRawDataSize());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// returns the CP from the array of value triplets
|
|
template <bool isOpen, typename FixedPointType>
|
|
Vec3 TBSplineVec3dPacked<isOpen, FixedPointType>::getCP (int nCP)
|
|
{
|
|
|
|
if (isOpen)
|
|
{
|
|
if (nCP < 0)
|
|
nCP = 0;
|
|
else
|
|
if (nCP >= this->numCPs())
|
|
nCP = this->numCPs()-1;
|
|
}
|
|
else
|
|
{
|
|
nCP = nCP % this->numCPs();
|
|
if (nCP < 0)
|
|
nCP += this->numCPs();
|
|
}
|
|
|
|
assert (nCP >= 0 && nCP < this->numCPs());
|
|
return this->m_PosScale->unpack(m_pData + this->numKnots()-2 + 3 * nCP);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// returns the normalized knot and the base - how many cycles the knot rolled back or forth
|
|
extern int PackedSplineClosedGetKnotTime(int &nKnot, int numKnots);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// returns the time
|
|
template <bool isOpen, typename FixedPointType>
|
|
float TBSplineVec3dPacked<isOpen, FixedPointType>::getKnotTime (int nKnot)const
|
|
{
|
|
if (!isOpen)
|
|
{
|
|
int nBase = PackedSplineClosedGetKnotTime(nKnot, this->numKnots());
|
|
|
|
if (nKnot == 0)
|
|
return this->m_TimeScale.getMin() + this->m_TimeScale.getRange()*nBase;
|
|
else
|
|
{
|
|
assert (nKnot < this->numKnots()-1);
|
|
return this->m_TimeScale.getRange()*nBase + this->m_TimeScale.unpack (m_pData[nKnot-1]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (nKnot <= 0)
|
|
return this->m_TimeScale.getMin();
|
|
else
|
|
if (nKnot >= this->numKnots()-1)
|
|
return this->m_TimeScale.getMax();
|
|
else
|
|
return this->m_TimeScale.unpack (m_pData[nKnot-1]);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// returns the max corner of the bounding box for CPs
|
|
template <bool isOpen, typename FixedPointType>
|
|
Vec3 TBSplineVec3dPackedDesc<isOpen, FixedPointType>::getCPMax ()const
|
|
{
|
|
return Vec3(this->m_PosScale[0].getMax(), this->m_PosScale[1].getMax(), this->m_PosScale[2].getMax());
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// returns the min corner of the bounding box for CPs
|
|
template <bool isOpen, typename FixedPointType>
|
|
Vec3 TBSplineVec3dPackedDesc<isOpen, FixedPointType>::getCPMin ()const
|
|
{
|
|
return Vec3(this->m_PosScale[0].getMin(), this->m_PosScale[1].getMin(), this->m_PosScale[2].getMin());
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// returns the min time
|
|
template <bool isOpen, typename FixedPointType>
|
|
float TBSplineVec3dPackedDesc<isOpen, FixedPointType>::getTimeMin() const
|
|
{
|
|
return this->m_TimeScale.getMin();
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// returns the max time
|
|
template <bool isOpen, typename FixedPointType>
|
|
float TBSplineVec3dPackedDesc<isOpen, FixedPointType>::getTimeMax () const
|
|
{
|
|
return this->m_TimeScale.getMax();
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// returns the max-min time
|
|
template <bool isOpen, typename FixedPointType>
|
|
float TBSplineVec3dPackedDesc<isOpen, FixedPointType>::getTimeRange () const
|
|
{
|
|
return this->m_TimeScale.getRange();
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// calculates the value of the spline at the specified point
|
|
template <bool isOpen, typename FixedPointType>
|
|
Vec3 TBSplineVec3dPacked<isOpen, FixedPointType>::getValue (float fTime)
|
|
{
|
|
int nInterval = findInterval (fTime);
|
|
assert (nInterval < 0 || nInterval >= this->numKnots()-1 || (getKnotTime (nInterval) <= fTime && fTime <= getKnotTime(nInterval+1)));
|
|
|
|
if (nInterval < 0)
|
|
return getCP(0);
|
|
|
|
if (nInterval >= this->numKnots()-1)
|
|
return getCP(this->numCPs()-1);
|
|
|
|
Vec3 vResult(0,0,0);
|
|
for (int i = 0; i >= -this->m_nDegree; --i)
|
|
{
|
|
Vec3 vCP = getCP(nInterval + (isOpen?this->m_nDegree:0) + i);
|
|
float fBasis = getBasis (nInterval + i, this->m_nDegree, fTime, nInterval);
|
|
vResult += vCP * fBasis;
|
|
}
|
|
|
|
return vResult;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// searches and returns the interval to which the given time belongs.
|
|
// each pair of knots defines interval [k1,k2)
|
|
// -1 is before the 0-th knot, numKnots()-1 is after the last knot
|
|
template <bool isOpen, typename FixedPointType>
|
|
int TBSplineVec3dPacked<isOpen, FixedPointType>::findInterval (float fTime)const
|
|
{
|
|
if (fTime < this->m_TimeScale.getMin())
|
|
return -1;
|
|
if (fTime < getKnotTime (1))
|
|
return 0;
|
|
if (fTime >= this->m_TimeScale.getMax())
|
|
return this->numKnots()-1;
|
|
if (fTime >= getKnotTime (this->numKnots()-2))
|
|
return this->numKnots()-2;
|
|
|
|
typename TBSplineVec3dPackedBase<isOpen,FixedPointType>::fixed fTimePacked = this->m_TimeScale.pack(fTime);
|
|
// depending on how we rounded the fTIme value, we seek either the bigger value or bigger or equal
|
|
if (fTime > this->m_TimeScale.unpack(fTimePacked))
|
|
// now, the time is clamped and can be safely packed
|
|
// search for the value that's bigger than fTimePacked
|
|
return std::upper_bound (m_pData, m_pData + this->numKnots()-2, fTimePacked) - m_pData;
|
|
else
|
|
// search for the fTimePacked or bigger value
|
|
return std::lower_bound (m_pData, m_pData + this->numKnots()-2, fTimePacked) - m_pData;
|
|
}
|
|
|
|
// returns the i-th basis function of degree d, given the time t
|
|
template <bool isOpen, typename FixedPointType>
|
|
float TBSplineVec3dPacked<isOpen, FixedPointType>::getBasis (int i, int d, float t) const
|
|
{
|
|
// the requested basis must have defined supporting knots
|
|
assert (i>= -d && i < this->numKnots()-1);
|
|
|
|
// starting and ending knots - they demark the support interval: [*begin,*(end-1)]
|
|
int nKnotBegin = i;
|
|
int nKnotEnd = nKnotBegin + d + 2;
|
|
// find the interval where the t is, among the supporting intervals
|
|
// the upper bound of that interval is searched for
|
|
int nKnotAfterT( nKnotBegin );
|
|
for ( ; nKnotAfterT < nKnotEnd && getKnotTime (nKnotAfterT) < t; ++nKnotAfterT)
|
|
continue;
|
|
|
|
if (nKnotAfterT == nKnotBegin)
|
|
{
|
|
assert (t < getKnotTime(nKnotBegin));
|
|
return 0; // the time t is before the supporting interval of the basis function
|
|
}
|
|
|
|
if (nKnotAfterT == nKnotEnd)
|
|
{
|
|
if (t > getKnotTime(nKnotEnd - 1))
|
|
return 0; // the time t is after the supporting interval
|
|
|
|
assert (t == getKnotTime (nKnotEnd - 1));
|
|
// scan down multiple knots
|
|
while (t == getKnotTime (nKnotAfterT - 1));
|
|
--nKnotAfterT;
|
|
}
|
|
|
|
return getBasis (nKnotBegin, d, t, nKnotAfterT - 1);
|
|
}
|
|
|
|
// returns the i-th basis function of degree d, given the time t and a hint, in which interval to search for it
|
|
template <bool isOpen, typename FixedPointType>
|
|
float TBSplineVec3dPacked<isOpen, FixedPointType>::getBasis (int i, int d, float t, int nIntervalT) const
|
|
{
|
|
if (nIntervalT < -d || nIntervalT >= this->numKnots()-1)
|
|
return 0;
|
|
|
|
assert (t >= getKnotTime(nIntervalT) && (t < getKnotTime(nIntervalT+1) || (t==getKnotTime(nIntervalT+1)&&getKnotTime(nIntervalT+1)==getKnotTime(nIntervalT))));
|
|
|
|
// the requested basis must have defined supporting knots
|
|
if (i < -d || i >= this->numKnots()-1)
|
|
return 0;
|
|
|
|
if (nIntervalT < i || nIntervalT > i + d)
|
|
return 0; // the time is outside supporting base
|
|
|
|
return getBasisUnsafe (i, d, t, nIntervalT);
|
|
}
|
|
|
|
// returns the value of the basis function of degree d, given the time t
|
|
// the knots of the basis function start at pKnotBegin, and the first knot before t is pKnotBeforeT
|
|
template <bool isOpen, typename FixedPointType>
|
|
float TBSplineVec3dPacked<isOpen, FixedPointType>::getBasisUnsafe (int nKnotBegin, int d, float t, int nKnotBeforeT)const
|
|
{
|
|
assert (t >= getKnotTime(nKnotBeforeT) && t <= getKnotTime(nKnotBeforeT+1));
|
|
assert (nKnotBegin >= -d && nKnotBegin < this->numKnots()-1);
|
|
assert (nKnotBeforeT >= nKnotBegin && nKnotBeforeT <= nKnotBegin + d);
|
|
|
|
switch (d)
|
|
{
|
|
case 0:
|
|
// trivial case
|
|
return 1;
|
|
case 1:
|
|
if (nKnotBeforeT == nKnotBegin)
|
|
{
|
|
// the t is in the first interval
|
|
return (t - getKnotTime(nKnotBegin)) / (getKnotTime(nKnotBegin+1) - getKnotTime(nKnotBegin));
|
|
}
|
|
else
|
|
{
|
|
assert (nKnotBeforeT == nKnotBegin + 1);
|
|
return (getKnotTime(nKnotBegin+2) - t) / (getKnotTime(nKnotBegin+2) - getKnotTime(nKnotBegin+1));
|
|
}
|
|
default:
|
|
{
|
|
float fResult = 0;
|
|
if (nKnotBeforeT < nKnotBegin + d)
|
|
fResult += getBasis (nKnotBegin, d-1, t, nKnotBeforeT) * (t - getKnotTime(nKnotBegin)) / (getKnotTime(nKnotBegin+d) - getKnotTime(nKnotBegin));
|
|
if (nKnotBeforeT > nKnotBegin)
|
|
fResult += getBasis (nKnotBegin+1, d-1, t, nKnotBeforeT) * (getKnotTime(nKnotBegin+d+1) - t) / (getKnotTime(nKnotBegin+d+1) - getKnotTime(nKnotBegin+1));
|
|
return fResult;
|
|
}
|
|
}
|
|
}
|
|
|
|
// apply the given scale to the spline (multiply the spline by scale
|
|
template <bool isOpen, typename FixedPointType>
|
|
void TBSplineVec3dPackedDesc<isOpen,FixedPointType>::scale (float fScale)
|
|
{
|
|
this->m_PosScale[0].scale (fScale);
|
|
this->m_PosScale[1].scale (fScale);
|
|
this->m_PosScale[2].scale (fScale);
|
|
}
|
|
|
|
typedef TBSplineVec3dPacked<true,unsigned char> BSplineVec3dPackedOpen;
|
|
typedef TBSplineVec3dPacked<false,unsigned char> BSplineVec3dPackedClosed;
|