You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

457 lines
11 KiB
C++

#ifndef INTERVAL_H
#define INTERVAL_H
namespace NSet
{
#define mIsEqual(x,y,eps) ( (x-y) < (eps) && (x-y) > (-eps) )
#define mIsZero(x, eps) ( (x) < (eps) && (x) > (-eps) )
//!\brief interval of values.
//Note that start does not need to be lower than stop. That's why there is a sort() method.
template <class T>
class TInterval
{
public:
inline TInterval();
inline TInterval(const T& start,const T& stop);
inline TInterval(const TInterval<T>& ti){ start=ti.start; stop=ti.stop; }
inline TInterval<T>& operator=(const TInterval<T>&);
inline bool operator==(const TInterval<T>&) const;
inline bool operator!=(const TInterval<T>&) const;
inline TInterval<T> operator+(const TInterval<T>&) const;
inline TInterval<T>& operator+=(const TInterval<T>&);
inline
virtual TInterval<T>* clone() const;
inline void set(const T& start,const T& stop);
inline bool isEqual(const TInterval<T>& i,const T& eps) const;
inline T width(bool allowrev=true) const;
inline virtual T center() const;
inline void shift(const T& len);
inline void widen(const T& len,bool allowrev=true);
inline virtual void scale(const T&);
inline T atIndex(int,const T& step) const;
inline bool isIncludes(const T&, bool allowrev=true ) const;
inline void include(const T&, bool allowrev=true);
inline void include(const TInterval<T>&,bool allowrev=true);
virtual void sort( bool asc=true );
inline bool isRev() const { return start > stop; }
virtual bool hasStep() const { return false; }
inline void Swap( T& a, T& b ) { T tmp = a; a = b; b = tmp; }
public:
T start;
T stop;
};
typedef TInterval<int> SampleGate;
typedef TInterval<float> ZGate;
template <class T>
inline void WINAPI Swap( T& a, T& b ) { T tmp = a; a = b; b = tmp; }
/*!\brief TInterval with step. */
template <class T>
class TIntervalStep : public TInterval<T>
{
public:
inline TIntervalStep();
inline TIntervalStep(const T& start,const T& stop, const T& step);
inline TIntervalStep(const TInterval<T>&);
inline TIntervalStep( const TIntervalStep<T>& si ): TInterval<T>(si), step(si.step) {}
inline TIntervalStep<T>& operator=(const TInterval<T>&);
inline bool operator==(const TIntervalStep<T>&) const;
inline bool operator!=(const TIntervalStep<T>&) const;
inline void getString(char* str) const;
inline void setString(char*);
inline
virtual TInterval<T>* clone() const;
inline void set(const T& start,const T& stop,const T& step);
inline bool isEqual(const TIntervalStep<T>& i,const T& eps) const;
inline T atIndex(int) const;
inline void Normalise(); //!< Makes sure start<stop and steps are non-zero
inline int getIndex( const double& t ) const;
inline int nearestIndex( const double& t ) const;
inline T snap( const double& t ) const;
inline int nrSteps() const;
inline float nrfSteps() const;
virtual inline void sort(bool asc=true);
inline void scale(const T&);
inline bool isCompatible(const TIntervalStep<T>&, float eps=mDefEps) const;
/*!< epsilon refers to the steps, i.e eps=0.1 allows b to be 0.1 steps apart.*/
inline T snapStep(const T& inpstep) const;
/*!<Snaps inpstep to a positive multiple of step. */
T step;
};
///////////////// ---------------- TInterval ---------------------///////////////////////////////////
template <class T>
inline TInterval<T>& TInterval<T>::operator=( const TInterval<T>& intv )
{
start = intv.start;
stop = intv.stop;
return *this;
}
template <class T> inline TInterval<T>::TInterval()
{
start = 0; stop = 0;
}
template <class T> inline TInterval<T>::TInterval( const T& t1, const T& t2 )
{
start = t1; stop = t2;
}
template <class T> inline
TInterval<T>* TInterval<T>::clone() const
{
return new TInterval<T>( *this );
}
template <class T> inline
void TInterval<T>::set( const T& t1, const T& t2 )
{
start = t1; stop = t2;
}
template <class T> inline
bool TInterval<T>::isEqual( const TInterval<T>& i, const T& eps ) const
{
return mIsEqual(start,i.start,eps) && mIsEqual(stop,i.stop,eps);
}
template <class T> inline
bool TInterval<T>::operator==( const TInterval<T>& i ) const
{
return start == i.start && stop == i.stop;
}
template <class T> inline
bool TInterval<T>::operator!=( const TInterval<T>& i ) const
{
return ! (i == *this);
}
template <class T> inline
TInterval<T> TInterval<T>::operator+( const TInterval<T>& i ) const
{
return TInterval<T>(start+i.start, stop+i.stop);
}
template <class T> inline
TInterval<T>& TInterval<T>::operator+=( const TInterval<T>& i )
{
start += i.start; stop += i.stop; return *this;
}
template <class T> inline
T TInterval<T>::width( bool allowrev ) const
{ return allowrev && isRev() ? start - stop : stop - start; }
template <class T> inline
T TInterval<T>::center() const
{
return (start+stop)/2;
}
template <class T> inline
void TInterval<T>::shift( const T& len )
{
start += len;
stop += len;
}
template <class T> inline
void TInterval<T>::widen( const T& len, bool allowrev )
{
if ( allowrev && isRev() )
{
start += len;
stop -= len;
}
else
{
start -= len;
stop += len;
}
}
template <class T> inline
void TInterval<T>::scale( const T& factor )
{ start *= factor; stop *= factor; }
template <class T> inline
bool TInterval<T>::isIncludes( const T& t, bool allowrev ) const
{
return allowrev && isRev() ? t>=stop && start>=t : t>=start && stop>=t;
}
template <class T> inline
void TInterval<T>::include( const T& i, bool allowrev )
{
if ( allowrev && isRev() )
{
if ( stop >i ) stop=i;
if ( start<i ) start=i;
}
else
{
if ( start>i ) start=i;
if ( stop <i ) stop=i;
}
}
template <class T> inline
void TInterval<T>::include( const TInterval<T>& i, bool allowrev )
{ include( i.start, allowrev ); include( i.stop, allowrev ); }
template <class T> inline
T TInterval<T>::atIndex( int idx, const T& step ) const
{ return start + step * idx; }
template <class T>
void TInterval<T>::sort( bool asc )
{
if ( (asc && stop<start) || (!asc && start<stop) )
Swap(start,stop);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// ---------------- TIntervalStep --------------------//////////////////////////////////
template <class T>
TIntervalStep<T>::TIntervalStep()
{ step = 1; }
template <class T>
TIntervalStep<T>::TIntervalStep( const T& t1, const T& t2, const T& t3 )
: TInterval<T>(t1,t2)
{ step = t3; }
template <class T>
TIntervalStep<T>::TIntervalStep( const TInterval<T>& intv )
: TInterval<T>(intv)
{
step = 1;
}
template <class T>
void TIntervalStep<T>::getString(char* str) const
{
if ( !str ) return;
double xx[3];
xx[0] = start;
xx[1] = stop;
xx[2] = step;
AfxGetBaseFunction()->PrintXYZ(str, xx, 3, ' ');
}
template <class T>
void TIntervalStep<T>::setString(char* str)
{
if ( !str ) return;
double xx[3];
sscanf_s( str, _T("%lf %lf %lf"), xx, xx+1, xx+2 );
start = (T)xx[0];
stop = (T)xx[1];
step = (T)xx[2];
}
template <class T> inline
TInterval<T>* TIntervalStep<T>::clone() const
{ return new TIntervalStep<T>( *this ); }
template <class T> inline
void TIntervalStep<T>::set( const T& t1, const T& t2, const T& t3 )
{ TInterval<T>::set( t1, t2 ); step = t3; }
template <class T> inline
bool TIntervalStep<T>::isEqual( const TIntervalStep<T>& i, const T& eps ) const
{ return TInterval<T>::isEqual(i,eps) && mIsEqual(step,i.step,eps); }
template <class T> inline
TIntervalStep<T>& TIntervalStep<T>::operator=(const TInterval<T>& ti)
{
start = ti.start;
stop = ti.stop;
return *this;
}
template <class T> inline
bool TIntervalStep<T>::operator==( const TIntervalStep<T>& i ) const
{ return TInterval<T>::operator==(i) && i.step==step; }
template <class T> inline
bool TIntervalStep<T>::operator!=( const TIntervalStep<T>& i ) const
{ return ! (i == *this); }
template <class T> inline
T TIntervalStep<T>::atIndex( int idx ) const
{ return TInterval<T>::atIndex(idx,step); }
template <class T>
int TIntervalStep<T>::getIndex( const double& t ) const
{ return (int)(( t - start ) / step); }
template <class T>
int TIntervalStep<T>::nearestIndex( const double& t ) const
{
int nr = getIndex(t);
const T atindex = atIndex(nr);
double reldiff = (t-atindex)/step;
if ( reldiff>=0.5 ) return nr+1;
else if ( reldiff<=-0.5 ) return nr-1;
return nr;
}
template <class T> inline
T TIntervalStep<T>::snap( const double& t ) const
{ return atIndex( nearestIndex( t ) ); }
template <class T> inline
void TIntervalStep<T>::sort( bool asc )
{
TInterval<T>::sort(asc);
if ( (asc && step < 0) || (!asc && step > 0) )
step = -step;
}
template <class T> inline
void TIntervalStep<T>::Normalise() //!< Makes sure start<stop and steps are non-zero
{
sort();
if(step == 0) step = 1;
}
template <class T> inline
void TIntervalStep<T>::scale( const T& factor )
{
TInterval<T>::scale( factor );
step *= factor;
}
template <class T> inline
T TIntervalStep<T>::snapStep( const T& inputstep ) const
{
const float relstep = (float) inputstep/step;
int nrsteps = AfxGetBaseFunction()->FloatToLong(relstep);
if ( nrsteps<1 ) nrsteps = 1;
return step*nrsteps;
}
template <class T> inline
float TIntervalStep<T>::nrfSteps() const
{
const float w = (float)TInterval<T>::width( true );
return w/step;
}
template <class T>
inline int TIntervalStep<T>::nrSteps() const
{
if ( !step ) return 0;
int ret = (((int)this->start) - this->stop) / step;
return ret < 0 ? -ret : ret;
}
#define mDefFNrSteps(typ,eps) \
template <> \
inline int TIntervalStep<typ>::nrSteps() const \
{ \
if ( !step ) return 0; \
typ ns = ( (start > stop ? start : stop) \
- (start > stop ? stop : start) ) \
/ (step > 0 ? step : -step); \
return (int)(ns * (1. + eps)); \
}
mDefFNrSteps(float,1e-4)
mDefFNrSteps(double,1e-8)
template <class T>
inline bool TIntervalStep<T>::isCompatible( const TIntervalStep<T>& b, float ) const
{
if ( step>b.step || b.step%step )
return false;
// const T diff = static_cast<const TInterval<T>*>(this)->start - b.start;
const T diff = this->start - b.start;
return !(diff%step);
}
#define mDefFltisCompat(typ) \
template <> \
inline bool TIntervalStep<typ>::isCompatible( const TIntervalStep<typ>& b, float eps ) const \
{ \
if ( !mIsEqual(step,b.step,eps) ) return false; \
\
typ nrsteps = (start - b.start) / step; \
int nrstepsi = AfxGetBaseFunction()->FloatToLong( nrsteps ); \
typ diff = nrsteps - nrstepsi; \
return ( (diff) < (eps) && (diff) > (-eps) ); \
}
mDefFltisCompat(float)
mDefFltisCompat(double)
}//namespace
using namespace NSet;
#endif //INTERVAL_H