#if !defined(AFX_LINEAPPROXIMATOR_H__F5E6E8DC_1185_4AC0_A061_7B3309700E9D__INCLUDED_)
#define AFX_LINEAPPROXIMATOR_H__F5E6E8DC_1185_4AC0_A061_7B3309700E9D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif
#ifndef UINT
#define UINT unsigned int
#endif
#ifndef ASSERT
#ifdef _DEBUG
#define ASSERT(a) if(!(a)) exit(-1);
#else
#define ASSERT(a)
#endif
#endif
#include <iostream>
#include <vector>
#include <list>
#include <limits>
namespace hull
{
template <class T>
class TLineApproximator
{
public:
struct SHomog
{
public:
SHomog(T _x=0, T _y=0, T _w=1) { x=_x; y=_y; w=_w;};
T x;
T y;
T w;
};
struct SPoint
{
public:
SPoint(T _x=0, T _y=0) { x=_x; y=_y;};
static void CrossProduct( const SPoint& p, const SPoint& q, SHomog& r)
{
r.w = p.x * q.y - p.y * q.x;
r.x = - q.y + p.y;
r.y = q.x - p.x;
};
static T DotProduct( const SPoint& p, const SHomog& q)
{
return q.w + p.x*q.x + p.y*q.y;
};
static T DotProduct( const SPoint& p, const SPoint& q)
{
return p.x*q.x + p.y*q.y;
};
static void LinComb( T a, const SPoint& p, T b, const SPoint& q, SPoint& r)
{
r.x = a * p.x + b * q.x;
r.y = a * p.y + b * q.y;
};
T x;
T y;
};
struct SLimits
{
T dMinX;
T dMaxX;
T dMinY;
T dMaxY;
T GetCenterX() { return (dMaxX+dMinX)/2.0;};
T GetCenterY() { return (dMaxX+dMinX)/2.0;};
T GetWidth() { return dMaxX-dMinX;};
T GetHeight() { return dMaxY-dMinY;};
};
typedef std::vector<SPoint> PointContainer;
typedef std::list<PointContainer::const_iterator> KeyContainer;
TLineApproximator(): m_dTol(0), m_bNormalization(true)
{m_limits.dMinX=m_limits.dMinY=0;m_limits.dMaxX=m_limits.dMaxY=1;};
~TLineApproximator(){};
UINT GetPointSize() const { return m_cPoints.size();};
void SetPoints( const std::vector<T>& vX, const std::vector<T>& vY);
PointContainer& GetPoints() { return m_cPoints;};
const PointContainer& GetPoints() const { return m_cPoints;};
UINT GetKeySize() const { return m_cKeys.size();};
KeyContainer& GetKeys() { return m_cKeys;};
const KeyContainer& GetKeys() const { return m_cKeys;};
void GetKeys( std::vector<T>& vX, std::vector<T>& vY);
void SetTol( double dTol) { m_dTol = __max( dTol, 0);};
double GetTol() const { return m_dTol;};
void SetNormalization( bool bEnabled = true) { m_bNormalization = true;};
bool IsNormalization() const { return m_bNormalization;};
void ClearKeys() { m_cKeys.clear();};
void Simplify();
UINT ShrinkNorm( double dScale, double dScaleTol = 0.05, UINT nMaxIter = 250);
UINT Shrink( UINT nDesiredPoints, UINT nTol = 10, UINT nMaxIter = 250);
void ComputeBoundingBox();
const SLimits& GetBoundingBox() const { return m_limits;};
void NormalizePoints();
void DeNormalizePoints();
protected:
virtual void ComputeKeys() { ClearKeys();};
private:
double m_dTol;
bool m_bNormalization;
PointContainer m_cPoints;
KeyContainer m_cKeys;
SLimits m_limits;
};
template <class T>
void TLineApproximator<T>::ComputeBoundingBox()
{
if (m_cPoints.size() < 2)
return;
PointContainer::const_iterator it = m_cPoints.begin();
m_limits.dMinX=m_limits.dMaxY=it->x;
m_limits.dMinY=m_limits.dMaxY=it->y;
it++;
for (;it!=m_cPoints.end();it++)
{
m_limits.dMaxX=__max( it->x, m_limits.dMaxX);
m_limits.dMaxY=__max( it->y, m_limits.dMaxY);
m_limits.dMinX=__min( it->x, m_limits.dMinX);
m_limits.dMinY=__min( it->y, m_limits.dMinY);
}
if ( fabs( m_limits.GetWidth() ) < std::numeric_limits<T>::epsilon() )
{
m_limits.dMaxX = m_limits.dMinX+1;
}
if ( fabs( m_limits.GetHeight() ) < std::numeric_limits<T>::epsilon() )
{
m_limits.dMaxY = m_limits.dMinY+1;
}
}
template <class T>
void TLineApproximator<T>::NormalizePoints()
{
T xm,ym,dx,dy;
xm=m_limits.GetCenterX();
ym=m_limits.GetCenterY();
dx=m_limits.GetWidth();
dy=m_limits.GetHeight();
PointContainer::iterator it;
for (it = m_cPoints.begin();it!=m_cPoints.end();it++)
{
it->x=(it->x-xm)/dx;
it->y=(it->y-ym)/dy;
}
}
template <class T>
void TLineApproximator<T>::DeNormalizePoints()
{
T xm,ym,dx,dy;
xm=m_limits.GetCenterX();
ym=m_limits.GetCenterY();
dx=m_limits.GetWidth();
dy=m_limits.GetHeight();
PointContainer::iterator it;
for (it = m_cPoints.begin();it!=m_cPoints.end();it++)
{
it->x=xm+it->x*dx;
it->y=ym+it->y*dy;
}
}
template <class T>
UINT TLineApproximator<T>::ShrinkNorm( double dScale, double dScaleTol, UINT nMaxIter)
{
UINT uWantedPoints= __min(m_cPoints.size(), __max(2, (UINT)floor(m_cPoints.size()*dScale)));
UINT uTol = __min(m_cPoints.size(), __max(0, (UINT)floor(m_cPoints.size()*dScaleTol) ));
return Shrink( uWantedPoints, uTol, nMaxIter);
}
template<class T>
UINT TLineApproximator<T>::Shrink( UINT nDesiredPoints, UINT nTol, UINT nMaxIter)
{
if (m_cPoints.size()<2)
return 0;
double dWantedPoints= __min(m_cPoints.size(), __max(2, nDesiredPoints));
double uMinWantedPoints = __min(m_cPoints.size(), __max(2, nDesiredPoints-nTol ));
double uMaxWantedPoints = __min(m_cPoints.size(), __max(2, nDesiredPoints+nTol ));
double eLeft, eRight, eMiddle;
double dResultLeft, dResultRight;
UINT iter=0;
if (m_bNormalization)
NormalizePoints();
eLeft = 0;
SetTol(eLeft);
ComputeKeys();
dResultLeft = m_cKeys.size();
iter++;
if ( (m_cKeys.size()<=uMaxWantedPoints) && (m_cKeys.size() >= uMinWantedPoints) )
goto PostProcess;
eRight=__max( m_limits.GetHeight(), m_limits.GetWidth() );
SetTol(eRight);
ComputeKeys();
dResultRight = m_cKeys.size();
iter++;
if ( (m_cKeys.size()<=uMaxWantedPoints) && (m_cKeys.size() >= uMinWantedPoints) )
goto PostProcess;
do
{
eMiddle=(eLeft +eRight)/2;
SetTol(eMiddle);
ComputeKeys();
std::cout<<"Iter: "<<iter<<", Wanted Keys "<<dWantedPoints<<", Current Keys "<<m_cKeys.size()<<", Tol (left, middle, right): ("
<<eLeft<<", "<<eMiddle<<", "<<eRight<<")\n";
if ( (m_cKeys.size()-dWantedPoints)*( dResultLeft-dResultRight) < 0 )
{
eRight=eMiddle;
dResultRight=m_cKeys.size();
}
else
{
eLeft=eMiddle;
dResultLeft=m_cKeys.size();
}
iter++;
} while ( ((m_cKeys.size()>uMaxWantedPoints) || (m_cKeys.size() < uMinWantedPoints))
&& (eRight - eLeft) > std::numeric_limits<T>::epsilon()
&& iter<nMaxIter );
PostProcess:
if (m_bNormalization)
DeNormalizePoints();
return iter;
}
template <class T>
void TLineApproximator<T>::Simplify()
{
if (m_cPoints.size()<2)
return;
if (m_bNormalization)
NormalizePoints();
ComputeKeys();
if (m_bNormalization)
DeNormalizePoints();
}
template<class T>
void TLineApproximator<T>::SetPoints( const std::vector<T>& vX, const std::vector<T>& vY)
{
ClearKeys();
UINT n = __min(vX.size(), vY.size());
m_cPoints.resize(n);
for (UINT i=0;i<n;i++)
{
m_cPoints[i].x=vX[i];
m_cPoints[i].y=vY[i];
}
ComputeBoundingBox();
}
template<class T>
void TLineApproximator<T>::GetKeys( std::vector<T>& vX, std::vector<T>& vY)
{
KeyContainer::const_iterator it;
UINT i;
vX.resize(m_cKeys.size());
VY.reisze(m_cKeys.size());
for (it = m_cKeys.begin(), i=0; it != m_cKeys.end(); it++, i++)
{
vX[i]=(*it)->x;
vY[i]=(*it)->y;
}
}
};
#endif