// PathHull.h: interface for the CPathHull class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_PATHHULL_H__50C639BA_585B_4272_9AF4_4632128D8938__INCLUDED_)
#define AFX_PATHHULL_H__50C639BA_585B_4272_9AF4_4632128D8938__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "LineApproximator.h"
namespace hull
{
#define DP_SGN(a) (a >= 0)
/*! \brief A path
\ingroup
*/
template<typename T, typename TPointContainer, typename TKeyContainer>
class TPathHull
{
public:
enum EStackOp
{
StackPushOp=0,
StackTopOp=1,
StackBotOp=2
};
typedef std::vector<signed char> OpContainer;
typedef std::vector<TPointContainer::const_iterator> PCItContainer;
TPathHull(): m_iHullMax(0)
{};
virtual ~TPathHull()
{};
void SetMaxSize(int iHullMax);
int GetHp() const { return m_iHp;};
int GetBot() const { return m_iBot;};
int GetTop() const { return m_iTop;};
const TPointContainer::const_iterator& GetpElt(int i) const { ASSERT(i<m_ppElt.size()); return m_ppElt[i];};
const TPointContainer::const_iterator& GetpHelt(int i) const { ASSERT(i<m_ppHelt.size()); return m_ppHelt[i];};
OpContainer& GetOps() { return m_pOp;};
void SetHp(int hp) { m_iHp=hp;};
void UpHp() { m_iHp++;};
void UpTop() { m_iTop++;};
void UpBot() { m_iBot++;};
void DownHp() { m_iHp--;};
void DownTop() { m_iTop--;};
void DownBot() { m_iBot--;};
void SetTopElt(const TPointContainer::const_iterator& p) { ASSERT(m_iTop>=0); ASSERT(m_iTop<m_ppElt.size()); m_ppElt[m_iTop]=p;};
void SetBotElt(const TPointContainer::const_iterator& p) { ASSERT(m_iBot>=0); ASSERT(m_iBot<m_ppElt.size()); m_ppElt[m_iBot]=p;};
void Split(const TPointContainer::const_iterator& e)
{
TPointContainer::const_iterator tmpe;
int tmpo;
ASSERT(m_iHp<m_ppHelt.size());
ASSERT(m_iHp<m_pOp.size());
while ((m_iHp >= 0)
&& ((tmpo = m_pOp[m_iHp]),
((tmpe = m_ppHelt[m_iHp]) != e) || (tmpo != StackPushOp)))
{
m_iHp--;
switch (tmpo)
{
case StackPushOp:
m_iTop--;
m_iBot++;
break;
case StackTopOp:
ASSERT(m_iTop-1>=0);
ASSERT(m_iTop+1<m_ppElt.size());
m_ppElt[++m_iTop] = tmpe;
break;
case StackBotOp:
ASSERT(m_iBot-1>=0);
ASSERT(m_iBot-1<m_ppElt.size());
m_ppElt[--m_iBot] = tmpe;
break;
}
}
}
void FindExtreme(const TLine<T,TPointContainer,TKeyContainer>::SHomog& line, TPointContainer::const_iterator* e, T& dist)
{
int sbase, sbrk, mid,lo, m1, brk, m2, hi;
T d1, d2;
if ((m_iTop - m_iBot) > 8)
{
lo = m_iBot; hi = m_iTop - 1;
sbase = SlopeSign(hi, lo, line);
do
{
brk = (lo + hi) / 2;
if (sbase == (sbrk = SlopeSign(brk, brk+1, line)))
if (sbase == (SlopeSign(lo, brk+1, line)))
lo = brk + 1;
else
hi = brk;
}
while (sbase == sbrk);
m1 = brk;
while (lo < m1)
{
mid = (lo + m1) / 2;
if (sbase == (SlopeSign(mid, mid+1, line)))
lo = mid + 1;
else
m1 = mid;
}
m2 = brk;
while (m2 < hi)
{
mid = (m2 + hi) / 2;
if (sbase == (SlopeSign(mid, mid+1, line)))
hi = mid;
else
m2 = mid + 1;
}
ASSERT(lo>=0);
ASSERT(lo <m_ppElt.size());
if ((d1 = TLine<T,TPointContainer,TKeyContainer>::DotProduct(*m_ppElt[lo], line)) < 0)
d1 = - d1;
ASSERT(m2>=0);
ASSERT(m2 <m_ppElt.size());
if ((d2 = TLine<T,TPointContainer,TKeyContainer>::DotProduct(*m_ppElt[m2], line)) < 0)
d2 = - d2;
dist = (d1 > d2 ? (*e = m_ppElt[lo], d1) : (*e = m_ppElt[m2], d2));
}
else /* Few DP_POINTs in hull */
{
dist = 0.0;
for (mid = m_iBot; mid < m_iTop; mid++)
{
ASSERT(mid>=0);
ASSERT(mid<m_ppElt->size());
if ((d1 = TLine<T,TPointContainer,TKeyContainer>::::DotProduct(*m_ppElt[mid], line)) < 0)
d1 = - d1;
if (d1 > *dist)
{
dist = d1;
*e = m_ppElt[mid];
}
}
}
}
void Init(const TPointContainer::const_iterator& e1, const TPointContainer::const_iterator& e2)
{
/* Initialize path hull and history */
ASSERT(m_iHullMax>=0);
ASSERT(m_iHullMax+1<m_ppElt.size());
m_ppElt[m_iHullMax] = e1;
m_ppElt[m_iTop = m_iHullMax + 1] =
m_ppElt[m_iBot = m_iHullMax - 1] =
m_ppHelt[m_iHp = 0] = e2;
m_pOp[0] = StackPushOp;
}
void Push(const TPointContainer::const_iterator& e)
{
ASSERT(m_iTop+1 >= 0);
ASSERT(m_iTop+1 < m_ppElt.size());
ASSERT(m_iBot-1 >= 0);
ASSERT(m_iBot-1 < m_ppElt.size());
ASSERT(m_iHp+1 >= 0);
ASSERT(m_iHp+1 < m_ppHelt.size());
ASSERT(m_iHp+1 < m_pOp.size());
/* Push element $e$ onto path hull $h$ */
m_ppElt[++m_iTop] = m_ppElt[--m_iBot] = m_ppHelt[++m_iHp] = e;
m_pOp[m_iHp] = StackPushOp;
}
void PopTop()
{
ASSERT(m_iTop >= 0);
ASSERT(m_iTop < m_ppElt.size());
ASSERT(m_iHp+1 >= 0);
ASSERT(m_iHp+1 < m_ppHelt.size());
ASSERT(m_iHp+1 < m_pOp.size());
m_ppHelt[++m_iHp] = m_ppElt[m_iTop--];
m_pOp[m_iHp] = StackTopOp;
}
void PopBot()
{
ASSERT(m_iBot >= 0);
ASSERT(m_iBot < m_ppElt.size());
ASSERT(m_iHp+1 >= 0);
ASSERT(m_iHp+1 < m_ppHelt.size());
ASSERT(m_iHp+1 < m_pOp.size());
/* Pop from bottom */
m_ppHelt[++m_iHp] = m_ppElt[m_iBot++];
m_pOp[m_iHp] = StackBotOp;
}
void Add(const TPointContainer::const_iterator& p)
{
int topflag, botflag;
topflag = LeftOfTop(p);
botflag = LeftOfBot(p);
if (topflag || botflag)
{
while (topflag)
{
PopTop();
topflag = LeftOfTop(p);
}
while (botflag)
{
PopBot();
botflag = LeftOfBot(p);
}
Push(p);
}
}
int LeftOfTop(const TPointContainer::const_iterator& c)
{
ASSERT(m_iTop >= 1);
ASSERT(m_iTop < m_ppElt.size());
/* Determine if point c is left of line a to b */
return (((*m_ppElt[m_iTop]).x - (*c).x)*((*m_ppElt[m_iTop-1]).y - (*c).y)
>= ((*m_ppElt[m_iTop-1]).x - (*c).x)*((*m_ppElt[m_iTop]).y - (*c).y));
}
int LeftOfBot(const TPointContainer::const_iterator& c)
{
ASSERT(m_iBot >= 0);
ASSERT(m_iBot+1 < m_ppElt.size());
/* Determine if point c is left of line a to b */
return (((*m_ppElt[m_iBot+1]).x - (*c).x)*((*m_ppElt[m_iBot]).y - (*c).y)
>= ((*m_ppElt[m_iBot]).x - (*c).x)*((*m_ppElt[m_iBot+1]).y - (*c).y));
}
int SlopeSign(int p, int q, const TLine<T,TPointContainer,TKeyContainer>::SHomog& l)
{
ASSERT(p >= 0);
ASSERT(p < m_ppElt.size());
ASSERT(q >= 0);
ASSERT(q < m_ppElt.size());
/* Return the sign of the projection
of $h[q] - h[p]$ onto the normal
to line $l$ */
return (int) (DP_SGN(
(l.x)*((*m_ppElt[q]).x - (*m_ppElt[p]).x)
+ (l.y)*((*m_ppElt[q]).y - (*m_ppElt[p]).y) ) ) ;
};
protected:
/// Maxium number of elements in hull
int m_iHullMax;
/// internal values
int m_iTop;
int m_iBot;
int m_iHp;
OpContainer m_pOp;
PCItContainer m_ppElt;
PCItContainer m_ppHelt;
};
template <typename T,typename TPointContainer,typename TKeyContainer>
void TPathHull<T,TPointContainer,TKeyContainer>::SetMaxSize(int iHullMax)
{
if (m_iHullMax == iHullMax)
return;
m_iHullMax=iHullMax;
m_pOp.resize(3*m_iHullMax);
m_ppElt.resize(2*m_iHullMax);
m_ppHelt.resize(3*m_iHullMax);
}
};
#endif // !defined(AFX_PATHHULL_H__50C639BA_585B_4272_9AF4_4632128D8938__INCLUDED_)